From 5500a262787760b0d7779844b22bcf211224b63b Mon Sep 17 00:00:00 2001 From: ling <1042585959@qq.com> Date: Sat, 1 Apr 2023 10:00:13 +0800 Subject: [PATCH] 5G --- rooter/0basicapps/ext-command/Makefile | 33 + .../usr/lib/lua/luci/controller/commands.lua | 296 ++ .../usr/lib/lua/luci/model/cbi/commands.lua | 37 + .../files/usr/lib/lua/luci/view/cmdedit.htm | 186 + .../files/usr/lib/lua/luci/view/commands.htm | 176 + .../ext-command/files/usr/lib/scripts/dummy | 1 + rooter/0basicapps/ext-extra/Makefile | 35 + .../ext-extra/files/etc/config/schedule | 7 + .../usr/lib/lua/luci/controller/schedule.lua | 13 + .../luci/model/cbi/admin_system/cronnew.lua | 29 + .../usr/lib/lua/luci/model/cbi/schedule.lua | 133 + .../files/usr/lib/rooter/luci/croncat.sh | 36 + .../files/usr/lib/rooter/luci/reboot.sh | 32 + rooter/0basicapps/ext-p910nd/Makefile | 36 + .../files/etc/uci-defaults/40_luci-p910ndx | 11 + .../usr/lib/lua/luci/controller/p910ndx.lua | 18 + .../usr/lib/lua/luci/model/cbi/p910ndx.lua | 59 + rooter/0basicapps/usb-storage/Makefile | 38 + .../usb-storage/files/etc/config/umount | 2 + .../files/etc/hotplug.d/block/20-mount | 68 + .../files/etc/hotplug.d/block/30-mount | 88 + .../files/etc/hotplug.d/block/99-mount | 41 + .../files/etc/uci-defaults/40_luci-hd_idle | 11 + .../0basicapps/usb-storage/files/etc/umount | 18 + .../usr/lib/lua/luci/controller/hd_idle.lua | 17 + .../usr/lib/lua/luci/controller/umount.lua | 11 + .../usr/lib/lua/luci/model/cbi/hd_idle.lua | 28 + .../usr/lib/lua/luci/model/cbi/umount.lua | 20 + .../files/usr/lib/sdcard/sdcard.sh | 88 + rooter/0basicsupport/ext-buttons/Makefile | 35 + .../ext-buttons/files/etc/btnaction.sh | 56 + .../files/etc/hotplug.d/button/00-button | 26 + .../files/etc/hotplug.d/button/10-buttonchk | 10 + .../ext-buttons/files/etc/init.d/buttons | 16 + .../usr/lib/lua/luci/controller/buttons.lua | 14 + .../lua/luci/model/cbi/buttons/buttons.lua | 44 + rooter/0basicsupport/ext-sms/Makefile | 35 + .../files/usr/lib/lua/luci/controller/sms.lua | 160 + .../usr/lib/lua/luci/view/rooter/sms.htm | 525 +++ .../ext-sms/files/usr/lib/sms/delsms.sh | 41 + .../ext-sms/files/usr/lib/sms/pack7bit.lua | 79 + .../ext-sms/files/usr/lib/sms/processsms | 168 + .../ext-sms/files/usr/lib/sms/sendsms.lua | 41 + .../ext-sms/files/usr/lib/sms/sendsms.sh | 10 + .../ext-sms/files/usr/lib/sms/smsout.lua | 24 + .../ext-sms/files/usr/lib/sms/smsout.sh | 38 + .../ext-sms/files/usr/lib/sms/smsread.lua | 862 +++++ .../ext-sms/files/usr/lib/sms/sys2sms.lua | 82 + .../ext-sms/files/usr/lib/sms/sys2sms.sh | 65 + .../ext-sms/files/usr/lib/sms/toggle.sh | 7 + .../ext-sms/files/usr/lib/sms/utf8togsm.lua | 167 + .../0basicsupport/luci-app-guestwifi/Makefile | 33 + .../files/etc/config/guestwifi | 4 + .../files/usr/lib/guestwifi/create.sh | 32 + .../files/usr/lib/guestwifi/remove.sh | 8 + .../files/usr/lib/guestwifi/start.sh | 200 + .../files/usr/lib/guestwifi/stop.sh | 19 + .../usr/lib/lua/luci/controller/guestwifi.lua | 22 + .../lib/lua/luci/model/cbi/guestwifi-edit.lua | 72 + .../usr/lib/lua/luci/model/cbi/guestwifi.lua | 128 + .../view/guestwifi/cbi-select-input-add.htm | 60 + .../lib/lua/luci/view/guestwifi/ovpn_css.htm | 38 + rooter/0drivers/rmbim/.svn/entries | 65 + .../rmbim/.svn/text-base/Makefile.svn-base | 45 + rooter/0drivers/rmbim/Makefile | 45 + .../rmbim/files/lib/netifd/proto/mbim.sh | 612 +++ .../files/usr/lib/rooter/mbim/mbimdata.sh | 115 + .../files/usr/lib/rooter/mbim/monitor.sh | 45 + rooter/0drivers/rqmi/Makefile | 52 + .../files/usr/lib/rooter/qmi/connectqmi.sh | 293 ++ rooter/0mesh/mesh-mesh/Makefile | 34 + .../mesh-mesh/files/etc/config/batman-adv | 16 + rooter/0mesh/mesh-mesh/files/etc/config/mesh | 18 + .../files/etc/hotplug.d/net/99-batman-gw | 34 + rooter/0mesh/mesh-mesh/files/etc/init.d/zmesh | 9 + .../usr/lib/lua/luci/controller/batman.lua | 249 ++ .../usr/lib/lua/luci/controller/mesh.lua | 76 + .../usr/lib/lua/luci/view/batman/batman.htm | 300 ++ .../usr/lib/lua/luci/view/mesh/mesh-setup.htm | 912 +++++ .../mesh-mesh/files/usr/lib/mesh/checker.sh | 251 ++ .../mesh-mesh/files/usr/lib/mesh/ping.sh | 34 + .../mesh-mesh/files/usr/lib/mesh/radio.sh | 78 + .../mesh-mesh/files/usr/lib/mesh/save.sh | 25 + .../mesh-mesh/files/usr/lib/mesh/savecfg.sh | 16 + .../mesh-mesh/files/usr/lib/mesh/startstop.sh | 8 + .../resources/dracula/dracula_graffle.js | 1 + .../resources/dracula/dracula_graph.js | 1 + .../resources/dracula/raphael-min.js | 7 + .../resources/jquery/jquery-1.4.js | 154 + .../luci-static/resources/protocol/batadv.js | 8 + .../resources/protocol/batadv_hardif.js | 8 + rooter/0mesh/mesh-wpad/Makefile | 29 + rooter/0optionalapps/bwallocate/Makefile | 34 + .../bwallocate/files/etc/init.d/textbwint | 14 + .../lib/lua/luci/controller/bwallocate.lua | 22 + .../lua/luci/model/cbi/fullmenu/bwmenu.lua | 267 ++ rooter/0optionalapps/bwmon/Makefile | 35 + .../bwmon/files/etc/config/bwmon | 9 + .../bwmon/files/etc/init.d/bwmon | 18 + .../bwmon/files/lib/upgrade/keep.d/bwmon | 1 + .../bwmon/files/usr/lib/bwmon/allocate.sh | 21 + .../bwmon/files/usr/lib/bwmon/amtleft.lua | 30 + .../files/usr/lib/bwmon/backup-daily.lua | 61 + .../bwmon/files/usr/lib/bwmon/backup-mon.lua | 81 + .../bwmon/files/usr/lib/bwmon/backup.sh | 51 + .../bwmon/files/usr/lib/bwmon/block | 28 + .../bwmon/files/usr/lib/bwmon/change.sh | 14 + .../bwmon/files/usr/lib/bwmon/chksms.sh | 21 + .../bwmon/files/usr/lib/bwmon/cleanup.lua | 32 + .../bwmon/files/usr/lib/bwmon/create.sh | 16 + .../bwmon/files/usr/lib/bwmon/create_data.lua | 193 + .../files/usr/lib/bwmon/data/placeholder | 1 + .../bwmon/files/usr/lib/bwmon/datainc.lua | 21 + .../bwmon/files/usr/lib/bwmon/dataper.lua | 16 + .../bwmon/files/usr/lib/bwmon/dotext.sh | 82 + .../bwmon/files/usr/lib/bwmon/editemail.sh | 29 + .../bwmon/files/usr/lib/bwmon/excede.sh | 94 + .../bwmon/files/usr/lib/bwmon/external.sh | 24 + .../bwmon/files/usr/lib/bwmon/float.lua | 9 + .../bwmon/files/usr/lib/bwmon/message | 4 + .../bwmon/files/usr/lib/bwmon/msmtprc | 12 + .../bwmon/files/usr/lib/bwmon/perday.lua | 204 + .../bwmon/files/usr/lib/bwmon/process.sh | 20 + .../bwmon/files/usr/lib/bwmon/rollover.sh | 11 + .../bwmon/files/usr/lib/bwmon/savetot.sh | 10 + .../bwmon/files/usr/lib/bwmon/sendsms.sh | 39 + .../bwmon/files/usr/lib/bwmon/textbw.sh | 153 + .../bwmon/files/usr/lib/bwmon/wrtbwmon.sh | 508 +++ .../usr/lib/lua/luci/controller/bwmon.lua | 119 + .../usr/lib/lua/luci/view/bwmon/bwmon.htm | 610 +++ .../bwmon/files/usr/sbin/readDB.awk | 157 + rooter/0optionalapps/ext-autoapn/Makefile | 33 + .../files/usr/lib/autoapn/apn.data | 2198 +++++++++++ rooter/0optionalapps/ext-blacklist/Makefile | 35 + .../ext-blacklist/files/etc/config/blacklist | 4 + .../files/usr/lib/blacklist/blacklist.sh | 32 + .../files/usr/lib/blacklist/chkblack.sh | 11 + .../usr/lib/lua/luci/controller/blacklist.lua | 13 + .../usr/lib/lua/luci/model/cbi/blacklist.lua | 21 + rooter/0optionalapps/ext-blockport/Makefile | 35 + .../ext-blockport/files/etc/config/blockport | 4 + .../files/usr/lib/blockport/blockport.sh | 37 + .../usr/lib/lua/luci/controller/blockport.lua | 15 + .../usr/lib/lua/luci/model/cbi/portblk.lua | 21 + rooter/0optionalapps/ext-domain/Makefile | 36 + .../ext-domain/files/etc/config/filter | 1 + .../ext-domain/files/etc/init.d/domain | 46 + .../ext-domain/files/usr/lib/domain/filter.sh | 26 + .../usr/lib/lua/luci/controller/domain.lua | 15 + .../usr/lib/lua/luci/model/cbi/domainfltr.lua | 21 + rooter/0optionalapps/ext-menu/Makefile | 35 + .../ext-menu/files/etc/uci-defaults/63-menu | 10 + .../usr/lib/fullmenu/full19/firewall.lua | 28 + .../lib/fullmenu/full19/luci-mod-status.json | 103 + .../lib/fullmenu/full19/luci-mod-system.json | 111 + .../files/usr/lib/fullmenu/full19/network.lua | 44 + .../files/usr/lib/fullmenu/full19/opkg.lua | 117 + .../fullmenu/full21/luci-app-firewall.json | 70 + .../lib/fullmenu/full21/luci-app-opkg.json | 13 + .../lib/fullmenu/full21/luci-mod-network.json | 98 + .../lib/fullmenu/full21/luci-mod-status.json | 137 + .../lib/fullmenu/full21/luci-mod-system.json | 136 + .../usr/lib/fullmenu/limited19/firewall.lua | 28 + .../fullmenu/limited19/luci-mod-status.json | 19 + .../fullmenu/limited19/luci-mod-system.json | 45 + .../usr/lib/fullmenu/limited19/network.lua | 44 + .../files/usr/lib/fullmenu/limited19/opkg.lua | 117 + .../fullmenu/limited21/luci-app-firewall.json | 70 + .../fullmenu/limited21/luci-mod-network.json | 98 + .../fullmenu/limited21/luci-mod-status.json | 38 + .../fullmenu/limited21/luci-mod-system.json | 60 + .../files/usr/lib/fullmenu/setmenu.sh | 34 + .../usr/lib/lua/luci/controller/fullmenu.lua | 28 + .../lib/lua/luci/view/fullmenu/fullmenu.htm | 166 + rooter/0optionalapps/ext-rspeedtest/Makefile | 34 + .../lib/lua/luci/controller/rspeedtest.lua | 79 + .../lua/luci/view/speedtest/rspeedtest.htm | 259 ++ .../files/usr/lib/speedtest/closest.lua | 62 + .../files/usr/lib/speedtest/getspeed.sh | 83 + .../files/usr/lib/speedtest/info.sh | 75 + .../files/usr/lib/speedtest/ping.sh | 26 + .../files/usr/lib/speedtest/servers.lua | 46 + .../files/usr/lib/speedtest/stop.sh | 28 + .../www/luci-static/resources/img/prov.png | Bin 0 -> 23789 bytes .../www/luci-static/resources/img/user.png | Bin 0 -> 15663 bytes rooter/0optionalapps/ext-speedtest/Makefile | 34 + .../usr/lib/lua/luci/controller/speedtest.lua | 11 + .../lib/lua/luci/view/speedtest/speedtest.htm | 45 + .../luci-static/speed/css/iconmoon_splash.css | 69 + .../www/luci-static/speed/css/splash.css | 341 ++ .../speed/fonts/icomoon_splash.eot | Bin 0 -> 4708 bytes .../speed/fonts/icomoon_splash.svg | 22 + .../speed/fonts/icomoon_splash.ttf | Bin 0 -> 4516 bytes .../speed/fonts/icomoon_splash.woff | Bin 0 -> 4592 bytes .../www/luci-static/speed/img/favicon.gif | Bin 0 -> 2441 bytes .../luci-static/speed/img/kangaroo_800.png | Bin 0 -> 5836 bytes rooter/0optionalapps/ext-texting/Makefile | 33 + .../ext-texting/files/etc/config/texting | 32 + .../ext-texting/files/etc/init.d/texting | 12 + .../files/usr/lib/fullmenu/chksms.sh | 21 + .../files/usr/lib/fullmenu/dotext.sh | 123 + .../files/usr/lib/fullmenu/text-setup.sh | 63 + .../usr/lib/lua/luci/controller/texting.lua | 32 + .../lua/luci/model/cbi/fullmenu/texting.lua | 254 ++ .../lib/lua/luci/view/fullmenu/textarea.htm | 103 + rooter/0optionalapps/ext-throttle/Makefile | 36 + .../ext-throttle/files/etc/config/sqm | 34 + .../files/etc/hotplug.d/iface/11-sqm | 27 + .../ext-throttle/files/etc/init.d/sqm | 31 + .../ext-throttle/files/etc/sqm/sqm.conf | 5 + .../files/etc/uci-defaults/50-luci-sqm | 12 + .../files/usr/lib/sqm/defaults.sh | 109 + .../files/usr/lib/sqm/functions.sh | 923 +++++ .../files/usr/lib/sqm/layer_cake.qos | 52 + .../files/usr/lib/sqm/layer_cake.qos.help | 4 + .../files/usr/lib/sqm/piece_of_cake.qos | 52 + .../files/usr/lib/sqm/piece_of_cake.qos.help | 4 + .../ext-throttle/files/usr/lib/sqm/run.sh | 130 + .../ext-throttle/files/usr/lib/sqm/simple.qos | 234 ++ .../files/usr/lib/sqm/simple.qos.help | 1 + .../files/usr/lib/sqm/simplest.qos | 104 + .../files/usr/lib/sqm/simplest.qos.help | 1 + .../files/usr/lib/sqm/simplest_tbf.qos | 85 + .../files/usr/lib/sqm/simplest_tbf.qos.help | 2 + .../ext-throttle/files/usr/lib/sqm/start-sqm | 66 + .../ext-throttle/files/usr/lib/sqm/stop-sqm | 54 + .../files/usr/lib/sqm/update-available-qdiscs | 14 + .../files/usr/lib/throttle/throttle.sh | 47 + rooter/0optionalapps/ext-wireguard/Makefile | 35 + .../ext-wireguard/files/etc/config/wireguard | 5 + .../files/etc/config/wireguard_recipes | 36 + .../ext-wireguard/files/etc/init.d/wireguard | 87 + .../usr/lib/lua/luci/controller/wireguard.lua | 111 + .../lua/luci/model/cbi/wireguard-client.lua | 99 + .../lua/luci/model/cbi/wireguard-server.lua | 130 + .../usr/lib/lua/luci/model/cbi/wireguard.lua | 182 + .../view/wireguard/cbi-select-input-add.htm | 111 + .../usr/lib/lua/luci/view/wireguard/conf.htm | 27 + .../lib/lua/luci/view/wireguard/ovpn_css.htm | 38 + .../lua/luci/view/wireguard/pageswitch.htm | 30 + .../lib/lua/luci/view/wireguard/text_conf.htm | 61 + .../lib/lua/luci/view/wireguard/wireguard.htm | 153 + .../files/usr/lib/wireguard/conf.sh | 118 + .../files/usr/lib/wireguard/create.sh | 76 + .../files/usr/lib/wireguard/keygen.sh | 63 + .../files/usr/lib/wireguard/startvpn.sh | 318 ++ .../files/usr/lib/wireguard/stopvpn.sh | 67 + .../files/usr/lib/wireguard/text.sh | 19 + .../luci-static/resources/icons/wireguard.png | Bin 0 -> 22762 bytes .../resources/icons/wireguard_disabled.png | Bin 0 -> 23205 bytes rooter/0optionalapps/ext-zerotier/Makefile | 34 + .../ext-zerotier/files/etc/init.d/zerofire | 37 + .../files/etc/uci-defaults/64-zerotier | 7 + .../usr/lib/lua/luci/controller/zerotier.lua | 62 + .../lua/luci/view/admin_status/index/zero.htm | 1 + .../lib/lua/luci/view/zerotier/zerotier.htm | 182 + .../lib/lua/luci/view/zerotier/zerotier1.htm | 22 + .../files/usr/lib/zerotier/netid.sh | 21 + rooter/0optionalapps/extramenu/Makefile | 33 + .../extramenu/files/etc/init.d/fullmenu | 18 + .../files/usr/lib/fullmenu/setmenu.sh | 18 + .../usr/lib/lua/luci/controller/fullmenu.lua | 39 + .../lib/lua/luci/view/fullmenu/fullmenu.htm | 181 + rooter/0optionalapps/libmicroxml/Makefile | 54 + .../luci-app-dnsmasq-ipset/Makefile | 34 + .../files/etc/config/dnsmasq-ipset | 5 + .../files/etc/init.d/dnsmasq-ipset | 49 + .../lib/lua/luci/controller/dnsmasq-ipset.lua | 15 + .../lib/lua/luci/model/cbi/dnsmasq-ipset.lua | 24 + .../0optionalapps/luci-app-hotspot/Makefile | 34 + .../files/etc/config/travelmate | 17 + .../etc/hotplug.d/iface/99-travelmate-iface | 46 + .../files/etc/init.d/travelmate | 90 + .../luci-app-hotspot/files/etc/init.d/zhot | 17 + .../files/lib/upgrade/keep.d/hotspot | 1 + .../luci-app-hotspot/files/usr/bin/hkillall | 9 + .../files/usr/lib/hotspot/band.sh | 25 + .../files/usr/lib/hotspot/copyhot.sh | 9 + .../files/usr/lib/hotspot/dis_hot.sh | 15 + .../files/usr/lib/hotspot/enable.sh | 42 + .../files/usr/lib/hotspot/getssid.sh | 15 + .../files/usr/lib/hotspot/inrange.sh | 59 + .../files/usr/lib/hotspot/manual.sh | 10 + .../files/usr/lib/hotspot/mode.sh | 19 + .../files/usr/lib/hotspot/reconn.sh | 11 + .../files/usr/lib/hotspot/travelmate.sh | 427 +++ .../usr/lib/lua/luci/controller/hotspot.lua | 307 ++ .../usr/lib/lua/luci/controller/wifilog.lua | 33 + .../usr/lib/lua/luci/view/hotspot/hotspot.htm | 1139 ++++++ .../usr/lib/lua/luci/view/wifilog/wifilog.htm | 32 + .../files/usr/lib/rooter/log/wifilogger.sh | 14 + .../luci-app-hotspot/files/usr/sbin/wifilog | 7 + .../resources/icons/encryption.png | Bin 0 -> 620 bytes rooter/0optionalapps/luci-app-iperf/Makefile | 34 + .../luci-app-iperf/files/etc/config/iperf | 96 + .../usr/lib/lua/luci/controller/iperf.lua | 56 + .../usr/lib/lua/luci/view/iperf/test.htm | 185 + .../usr/share/luci/menu.d/luci-app-iperf.json | 13 + .../usr/share/rpcd/acl.d/luci-app-iperf.json | 11 + .../0optionalapps/luci-app-rootervpn/Makefile | 34 + .../files/etc/config/openvpn_recipes | 293 ++ .../files/etc/init.d/openvpn | 194 + .../files/etc/init.d/rootervpn | 183 + .../files/etc/openvpn/airvpn/ca.crt | 36 + .../files/etc/openvpn/airvpn/client.crt | 38 + .../files/etc/openvpn/airvpn/client.key | 52 + .../files/etc/openvpn/airvpn/ta.key | 18 + .../files/etc/openvpn/mullvad/mullvad_ca.crt | 109 + .../files/etc/openvpn/mullvad/mullvad_crl.pem | 36 + .../files/etc/openvpn/pia/ca.rsa.2048.crt | 33 + .../files/etc/openvpn/pia/crl.rsa.2048.pem | 15 + .../etc/openvpn/placeholder/placeholder.file | 2 + .../files/etc/openvpn/windscribe/ca.crt | 34 + .../files/etc/openvpn/windscribe/ta.key | 18 + .../files/lib/upgrade/keep.d/rootervpn | 1 + .../files/usr/bin/ovpn-userpass | 16 + .../luci-app-rootervpn/files/usr/bin/rkillall | 9 + .../files/usr/lib/easyrsa/dns.sh | 67 + .../files/usr/lib/easyrsa/firewall.sh | 73 + .../files/usr/lib/easyrsa/generate.sh | 131 + .../files/usr/lib/easyrsa/stop.sh | 11 + .../files/usr/lib/easyrsa/vpn.sh | 9 + .../files/usr/lib/easyrsa/vpng.sh | 128 + .../usr/lib/lua/luci/controller/openvpn.lua | 135 + .../lua/luci/model/cbi/openvpn-advanced.lua | 902 +++++ .../lib/lua/luci/model/cbi/openvpn-basic.lua | 196 + .../lib/lua/luci/model/cbi/openvpn-file.lua | 82 + .../lib/lua/luci/model/cbi/openvpn-server.lua | 86 + .../usr/lib/lua/luci/model/cbi/openvpn.lua | 179 + .../lua/luci/view/admin_status/index/vpn.htm | 1 + .../usr/lib/lua/luci/view/easyrsa/easyrsa.htm | 172 + .../view/openvpn/cbi-select-input-add.htm | 111 + .../lib/lua/luci/view/openvpn/ovpn_css.htm | 38 + .../lib/lua/luci/view/openvpn/pageswitch.htm | 30 + .../usr/lib/lua/luci/view/openvpn/vpn1.htm | 120 + .../resources/icons/vpn-disabled.png | Bin 0 -> 1014 bytes .../resources/icons/vpn-started.png | Bin 0 -> 858 bytes .../resources/icons/vpn-stopped.png | Bin 0 -> 886 bytes rooter/0optionalapps/pingtest/Makefile | 36 + .../files/usr/lib/custom/johns_ping.sh | 99 + .../files/usr/lib/custom/test_ping.sh | 35 + .../usr/lib/lua/luci/controller/ping.lua | 16 + .../files/usr/lib/lua/luci/model/cbi/ping.lua | 42 + .../luci/view/admin_status/index/extping.htm | 1 + .../lib/lua/luci/view/pingtest/extping.htm | 26 + rooter/0optionalapps/qfirehose/Makefile | 40 + rooter/0optionalapps/qfirehose/src/Makefile | 7 + .../qfirehose/src/firehose_protocol.c | 1087 ++++++ .../qfirehose/src/hostdl_packet.h | 178 + rooter/0optionalapps/qfirehose/src/md5.c | 343 ++ rooter/0optionalapps/qfirehose/src/md5.h | 23 + .../0optionalapps/qfirehose/src/qfirehose.c | 635 ++++ .../qfirehose/src/sahara_protocol.c | 375 ++ .../qfirehose/src/sahara_protocol.h | 385 ++ .../qfirehose/src/stream_download_protocol.c | 766 ++++ rooter/0optionalapps/qfirehose/src/usb2tcp.c | 338 ++ .../0optionalapps/qfirehose/src/usb_linux.c | 1170 ++++++ .../0optionalapps/qfirehose/src/usb_linux.h | 142 + rooter/0optionalapps/qlog/Makefile | 41 + .../T1.LinuxData-OTA-DataService-AP_V01.cfg | Bin 0 -> 2012 bytes .../usr/lib/conf/T2.RegServ-CotextAct_V01.cfg | Bin 0 -> 2260 bytes .../lib/conf/T3.SimpleData-(TCPUDP)_V01.cfg | Bin 0 -> 2144 bytes .../files/usr/lib/conf/T4.Throughput_V01.cfg | Bin 0 -> 2116 bytes .../files/usr/lib/conf/T5.COMMON-T1T4_V01.cfg | Bin 0 -> 4226 bytes ...T6.FullMessage.SimpleLogPacket(AT)_V01.cfg | Bin 0 -> 4191 bytes .../files/usr/lib/conf/T7.V2X_ALL_V01.cfg | Bin 0 -> 2205 bytes .../qlog/files/usr/lib/conf/default.cfg | Bin 0 -> 3480 bytes rooter/0optionalapps/qlog/src/Makefile | 8 + rooter/0optionalapps/qlog/src/asr.c | 87 + rooter/0optionalapps/qlog/src/main.c | 499 +++ rooter/0optionalapps/qlog/src/mdm.c | 203 + rooter/0optionalapps/qlog/src/qlog.h | 44 + rooter/0optionalapps/qlog/src/sahara.c | 660 ++++ .../0optionalapps/qlog/src/sahara_protocol.h | 510 +++ rooter/0optionalapps/qlog/src/tty2tcp.c | 174 + rooter/0optionalapps/udp-tunnel/Makefile | 40 + rooter/0optionalapps/udp-tunnel/src/Makefile | 36 + rooter/0optionalapps/udp-tunnel/src/log.c | 130 + rooter/0optionalapps/udp-tunnel/src/log.h | 67 + rooter/0optionalapps/udp-tunnel/src/network.c | 401 ++ rooter/0optionalapps/udp-tunnel/src/network.h | 40 + .../0optionalapps/udp-tunnel/src/udptunnel.c | 523 +++ rooter/0optionalapps/udp-tunnel/src/utils.c | 32 + rooter/0optionalapps/udp-tunnel/src/utils.h | 55 + rooter/0optionalapps/webconsole/Makefile | 35 + .../lib/lua/luci/controller/webconsole.lua | 31 + .../usr/lib/lua/luci/view/web/web_console.htm | 51 + rooter/0protocols/luci-proto-3x/Makefile | 53 + .../luci/model/cbi/admin_network/proto_3x.lua | 146 + .../lib/lua/luci/model/network/proto_3x.lua | 49 + .../www/luci-static/resources/protocol/3x.js | 11 + rooter/0protocols/luci-proto-mbim/Makefile | 53 + .../model/cbi/admin_network/proto_mbim.lua | 45 + .../lib/lua/luci/model/network/proto_mbim.lua | 55 + .../luci-static/resources/protocol/mbim.js | 107 + rooter/0routerspecfic/alix2d13/Makefile | 35 + .../alix2d13/files/usr/lib/rooter/special.sh | 7 + rooter/0routerspecfic/apu2c4/Makefile | 33 + rooter/0routerspecfic/b1300/Makefile | 35 + .../b1300/files/usr/lib/rooter/special.sh | 30 + rooter/0routerspecfic/d240/Makefile | 35 + .../d240/files/usr/lib/sdcard/sdcard.sh | 14 + rooter/0routerspecfic/dir860l/Makefile | 35 + .../files/etc/hotplug.d/iface/99-dir860-led | 13 + .../dir860l/files/usr/lib/rooter/special.sh | 8 + rooter/0routerspecfic/ext-ssh/Makefile | 36 + .../ext-ssh/files/etc/init.d/sshd | 54 + .../ext-ssh/files/etc/ssh/moduli | 407 ++ .../ext-ssh/files/etc/ssh/ssh_config | 49 + .../ext-ssh/files/etc/ssh/ssh_host_ecdsa_key | 5 + .../files/etc/ssh/ssh_host_ecdsa_key.pub | 1 + .../files/etc/ssh/ssh_host_ed25519_key | 7 + .../files/etc/ssh/ssh_host_ed25519_key.pub | 1 + .../ext-ssh/files/etc/ssh/ssh_host_rsa_key | 27 + .../files/etc/ssh/ssh_host_rsa_key.pub | 1 + .../ext-ssh/files/etc/ssh/sshd_config | 120 + rooter/0routerspecfic/fscheck/Makefile | 36 + .../usr/lib/lua/luci/controller/filecheck.lua | 37 + .../lua/luci/view/admin_system/filecheck.htm | 104 + .../fscheck/files/usr/lib/rooter/filecheck.sh | 19 + rooter/0routerspecfic/h721/Makefile | 36 + .../h721/files/etc/exportgpio.sh | 24 + .../h721/files/etc/init.d/custom | 10 + .../h721/files/etc/init.d/exportgpio | 15 + .../h721/files/usr/lib/custom/custom.lua | 38 + .../h721/files/usr/lib/custom/hostname.sh | 10 + .../h721/files/usr/lib/custom/wifi.sh | 30 + .../h721/files/usr/lib/rooter/modem-led.sh | 94 + .../h721/files/usr/lib/rooter/special.sh | 4 + rooter/0routerspecfic/mt1300/Makefile | 35 + .../mt1300/files/etc/init.d/mt1300 | 23 + rooter/0routerspecfic/rbm11g/Makefile | 35 + .../rbm11g/files/usr/lib/rooter/modem-led.sh | 124 + .../rbm11g/files/usr/lib/rooter/special.sh | 11 + rooter/0routerspecfic/rbm33g/Makefile | 35 + .../rbm33g/files/usr/lib/rooter/special.sh | 70 + rooter/0routerspecfic/rbsxtr/Makefile | 35 + .../files/etc/uci-defaults/40_luci-theme | 11 + .../rbsxtr/files/usr/lib/rooter/modem-led.sh | 34 + .../www/luci-static/background/main_bg.jpg | Bin 0 -> 34809 bytes .../rbsxtr/files/www/luci-static/img/open.png | Bin 0 -> 41195 bytes rooter/0routerspecfic/rd05a1/Makefile | 37 + .../rd05a1/files/etc/init.d/pciepwr | 18 + rooter/0routerspecfic/vpnpolicy/Makefile | 31 + rooter/0routerspecfic/we826/Makefile | 35 + .../we826/files/etc/init.d/wd-init | 14 + .../we826/files/usr/lib/custom/watchdog.sh | 19 + rooter/0routerspecfic/we826q/Makefile | 35 + .../we826q/files/etc/init.d/wd-init | 14 + .../we826q/files/usr/lib/custom/watchdog.sh | 25 + rooter/0routerspecfic/wg1602/Makefile | 36 + .../wg1602/files/etc/init.d/sw-init | 15 + .../wg1602/files/usr/lib/rooter/special.sh | 28 + rooter/0routerspecfic/wg1608/Makefile | 36 + .../wg1608/files/etc/init.d/wd-init | 15 + .../wg1608/files/usr/lib/custom/watchdog.sh | 23 + .../wg1608/files/usr/lib/rooter/modem-led.sh | 51 + .../wg1608/files/usr/lib/rooter/special.sh | 15 + rooter/0routerspecfic/wg209/Makefile | 33 + .../wg209/files/usr/lib/rooter/modem-led.sh | 76 + rooter/0routerspecfic/wg259/Makefile | 34 + .../wg259/files/usr/lib/rooter/special.sh | 23 + rooter/0routerspecfic/wg3526/Makefile | 33 + .../wg3526/files/usr/lib/rooter/special.sh | 19 + rooter/0routerspecfic/wg827/Makefile | 36 + .../wg827/files/usr/lib/rooter/modem-led.sh | 38 + rooter/0routerspecfic/wrt1900/Makefile | 35 + .../wrt1900/files/etc/init.d/amsdu | 14 + rooter/0routerspecfic/x750/Makefile | 33 + .../x750/files/usr/lib/rooter/special.sh | 23 + rooter/0splash/ext-splash/Makefile | 35 + .../ext-splash/files/etc/config/iframe | 17 + .../ext-splash/files/etc/init.d/iframeint | 18 + .../ext-splash/files/usr/lib/iframe/band.html | 1 + .../ext-splash/files/usr/lib/iframe/bwdays.sh | 109 + .../files/usr/lib/iframe/bwtemplate.html | 85 + .../ext-splash/files/usr/lib/iframe/create.sh | 31 + .../files/usr/lib/iframe/daylist.html | 85 + .../files/usr/lib/iframe/iframe.html | 41 + .../files/usr/lib/iframe/image.html | 11 + .../files/usr/lib/iframe/modem2.html | 1 + .../ext-splash/files/usr/lib/iframe/open.html | 1 + .../files/usr/lib/iframe/speed.html | 114 + .../files/usr/lib/iframe/status.html | 150 + .../ext-splash/files/usr/lib/iframe/status.sh | 21 + .../files/usr/lib/iframe/stupdate.sh | 352 ++ .../ext-splash/files/usr/lib/iframe/update.sh | 95 + .../files/usr/lib/iframe/zerotier.html | 14 + .../files/www/luci-static/display.html | 1 + .../files/www/luci-static/iframe.html | 1 + .../files/www/luci-static/ifstatus.html | 1 + .../rooter/css/iconmoon_splash.css | 69 + .../www/luci-static/rooter/css/splash.css | 342 ++ .../rooter/fonts/icomoon_splash.eot | Bin 0 -> 4708 bytes .../rooter/fonts/icomoon_splash.svg | 22 + .../rooter/fonts/icomoon_splash.ttf | Bin 0 -> 4516 bytes .../rooter/fonts/icomoon_splash.woff | Bin 0 -> 4592 bytes .../www/luci-static/rooter/img/favicon.gif | Bin 0 -> 2441 bytes .../luci-static/rooter/img/kangaroo_800.png | Bin 0 -> 5836 bytes .../files/www/splash_files/check1.gif | Bin 0 -> 49 bytes rooter/0splash/ext-splashconfig/Makefile | 36 + .../usr/lib/lua/luci/controller/splash.lua | 13 + .../usr/lib/lua/luci/model/cbi/splashm.lua | 44 + rooter/0splash/splash/Makefile | 35 + .../rooter/css/iconmoon_splash.css | 69 + .../www/luci-static/rooter/css/splash.css | 311 ++ .../rooter/fonts/icomoon_splash.eot | Bin 0 -> 4708 bytes .../rooter/fonts/icomoon_splash.svg | 22 + .../rooter/fonts/icomoon_splash.ttf | Bin 0 -> 4516 bytes .../rooter/fonts/icomoon_splash.woff | Bin 0 -> 4592 bytes .../www/luci-static/rooter/img/favicon.gif | Bin 0 -> 2441 bytes .../luci-static/rooter/img/kangaroo_800.png | Bin 0 -> 5836 bytes rooter/0splash/splash/files/www/splash.html | 101 + .../files/www/splash_files/cellular.png | Bin 0 -> 8344 bytes .../splash/files/www/splash_files/check.gif | Bin 0 -> 49 bytes .../splash/files/www/splash_files/check.jpg | Bin 0 -> 631 bytes .../splash/files/www/splash_files/forum.png | Bin 0 -> 3845 bytes .../splash/files/www/splash_files/home.png | Bin 0 -> 1262 bytes .../splash/files/www/splash_files/kanga1.png | Bin 0 -> 2532 bytes .../splash/files/www/splash_files/openwrt.png | Bin 0 -> 2422 bytes .../splash/files/www/splash_files/rooter.png | Bin 0 -> 311293 bytes rooter/0splash/splash/files/www/status.html | 254 ++ rooter/0splash/status/Makefile | 35 + rooter/0splash/status/files/etc/config/splash | 4 + .../usr/lib/lua/luci/controller/splashset.lua | 11 + .../usr/lib/lua/luci/model/cbi/splash.lua | 22 + .../status/files/usr/lib/splash/check.gif | Bin 0 -> 49 bytes .../status/files/usr/lib/splash/full.gif | Bin 0 -> 49 bytes .../status/files/usr/lib/splash/splash.sh | 21 + .../rooter/css/iconmoon_splash.css | 69 + .../www/luci-static/rooter/css/splash.css | 311 ++ .../rooter/fonts/icomoon_splash.eot | Bin 0 -> 4708 bytes .../rooter/fonts/icomoon_splash.svg | 22 + .../rooter/fonts/icomoon_splash.ttf | Bin 0 -> 4516 bytes .../rooter/fonts/icomoon_splash.woff | Bin 0 -> 4592 bytes .../www/luci-static/rooter/img/favicon.gif | Bin 0 -> 2441 bytes .../luci-static/rooter/img/kangaroo_800.png | Bin 0 -> 5836 bytes rooter/0splash/status/files/www/splash.html | 264 ++ .../files/www/splash_files/cellular.png | Bin 0 -> 8344 bytes .../status/files/www/splash_files/check.jpg | Bin 0 -> 631 bytes .../status/files/www/splash_files/forum.png | Bin 0 -> 3845 bytes .../status/files/www/splash_files/home.png | Bin 0 -> 1262 bytes .../status/files/www/splash_files/kanga1.png | Bin 0 -> 2532 bytes .../status/files/www/splash_files/openwrt.png | Bin 0 -> 2422 bytes .../status/files/www/splash_files/rooter.png | Bin 0 -> 311293 bytes .../0splash/status/files/www/splashfull.html | 101 + .../0splash/status/files/www/statusfull.html | 271 ++ rooter/ext-rooter-basic/Makefile | 43 + rooter/ext-rooter-basic/files/etc/codename | 1 + .../ext-rooter-basic/files/etc/config/custom | 64 + .../ext-rooter-basic/files/etc/config/modem | 18 + .../ext-rooter-basic/files/etc/config/profile | 19 + rooter/ext-rooter-basic/files/etc/config/ttl | 11 + .../files/etc/config/variable | 4 + rooter/ext-rooter-basic/files/etc/genericcmd | 4 + rooter/ext-rooter-basic/files/etc/header_msg | 4 + .../files/etc/hotplug.d/iface/10-lan | 27 + .../files/etc/hotplug.d/iface/19-rooter | 42 + .../files/etc/hotplug.d/tty/30-3x | 31 + .../files/etc/hotplug.d/usb/20-usb_mode | 3 + .../ext-rooter-basic/files/etc/init.d/clear | 21 + .../ext-rooter-basic/files/etc/init.d/iphone | 22 + .../ext-rooter-basic/files/etc/init.d/rooter | 9 + .../ext-rooter-basic/files/etc/init.d/usbmode | 14 + ...000000000000000000000000000000000000.plist | 0 rooter/ext-rooter-basic/files/etc/netspeed | 1 + rooter/ext-rooter-basic/files/etc/newstyle | 0 rooter/ext-rooter-basic/files/etc/quectelcmd | 6 + rooter/ext-rooter-basic/files/etc/sierracmd | 4 + rooter/ext-rooter-basic/files/etc/ttl.user | 4 + .../ext-rooter-basic/files/etc/usb-mode.json | 3180 ++++++++++++++++ .../files/lib/netifd/proto/3x.sh | 171 + .../files/lib/upgrade/keep.d/cronfiles | 2 + .../files/lib/upgrade/keep.d/rc-local | 3 + .../ext-rooter-basic/files/usr/bin/bmask128 | 19 + .../files/usr/bin/chan2band.sh | 317 ++ .../ext-rooter-basic/files/usr/bin/encodemask | 24 + .../ext-rooter-basic/files/usr/bin/jkillall | 9 + .../ext-rooter-basic/files/usr/bin/rsrp2rssi | 21 + .../ext-rooter-basic/files/usr/bin/set_gpio | 18 + .../files/usr/lib/custom/locktype.sh | 22 + .../files/usr/lib/custom/ttlx.sh | 11 + .../files/usr/lib/gps/smsreply.sh | 115 + .../lib/lua/luci/controller/admin/modem.lua | 664 ++++ .../usr/lib/lua/luci/controller/modlog.lua | 29 + .../usr/lib/lua/luci/controller/poweroff.lua | 16 + .../usr/lib/lua/luci/controller/profile.lua | 40 + .../lib/lua/luci/model/cbi/firewall/ttlx.lua | 30 + .../lua/luci/model/cbi/rooter/customize.lua | 156 + .../lua/luci/model/cbi/rooter/profiles.lua | 828 +++++ .../luci/view/admin_status/index/external.htm | 1 + .../lua/luci/view/admin_system/poweroff.htm | 34 + .../usr/lib/lua/luci/view/modlog/modlog.htm | 32 + .../usr/lib/lua/luci/view/rooter/bandlock.htm | 26 + .../usr/lib/lua/luci/view/rooter/custom.htm | 126 + .../usr/lib/lua/luci/view/rooter/debug.htm | 87 + .../usr/lib/lua/luci/view/rooter/external.htm | 26 + .../usr/lib/lua/luci/view/rooter/log.htm | 54 + .../usr/lib/lua/luci/view/rooter/misc.htm | 2387 ++++++++++++ .../lib/lua/luci/view/rooter/net_status.htm | 564 +++ .../usr/lib/lua/luci/view/rooter/profile.htm | 75 + .../files/usr/lib/modlog/modlogger.sh | 20 + .../files/usr/lib/profile/loadcfg.sh | 14 + .../files/usr/lib/profile/restart.sh | 18 + .../files/usr/lib/profile/savecfg.sh | 16 + .../files/usr/lib/rooter/autoapn.sh | 7 + .../files/usr/lib/rooter/cdmafind.lua | 55 + .../files/usr/lib/rooter/chan2band.sh | 273 ++ .../usr/lib/rooter/common/fibocomdata.sh | 476 +++ .../files/usr/lib/rooter/common/gettype.sh | 213 ++ .../files/usr/lib/rooter/common/huaweidata.sh | 299 ++ .../files/usr/lib/rooter/common/lockchk.sh | 104 + .../usr/lib/rooter/common/mdm9215data.sh | 127 + .../files/usr/lib/rooter/common/meigdata.sh | 281 ++ .../files/usr/lib/rooter/common/modemchk.lua | 120 + .../usr/lib/rooter/common/novateldata.sh | 138 + .../files/usr/lib/rooter/common/otherdata.sh | 97 + .../files/usr/lib/rooter/common/phone.sh | 55 + .../files/usr/lib/rooter/common/processat.sh | 16 + .../files/usr/lib/rooter/common/quantadata.sh | 121 + .../usr/lib/rooter/common/quecteldata.sh | 376 ++ .../files/usr/lib/rooter/common/sierradata.sh | 258 ++ .../files/usr/lib/rooter/common/simcomdata.sh | 172 + .../files/usr/lib/rooter/common/t77data.sh | 236 ++ .../files/usr/lib/rooter/common/telitdata.sh | 241 ++ .../files/usr/lib/rooter/common/ubloxdata.sh | 250 ++ .../files/usr/lib/rooter/common/ztedata.sh | 193 + .../files/usr/lib/rooter/connect/bandmask | 483 +++ .../files/usr/lib/rooter/connect/conmon.sh | 188 + .../usr/lib/rooter/connect/create_connect.sh | 1360 +++++++ .../usr/lib/rooter/connect/create_hostless.sh | 666 ++++ .../usr/lib/rooter/connect/create_iphone.sh | 222 ++ .../usr/lib/rooter/connect/disablemw3.sh | 14 + .../usr/lib/rooter/connect/disconnect.sh | 73 + .../usr/lib/rooter/connect/get_profile.sh | 423 +++ .../files/usr/lib/rooter/connect/handlettl.sh | 106 + .../usr/lib/rooter/connect/postconnect.sh | 19 + .../usr/lib/rooter/connect/preconnect.sh | 15 + .../usr/lib/rooter/connect/reconnect-ppp.sh | 59 + .../files/usr/lib/rooter/connect/reconnect.sh | 12 + .../files/usr/lib/rooter/customname.lua | 17 + .../files/usr/lib/rooter/gcom/auto.gcom | 31 + .../files/usr/lib/rooter/gcom/baseinfo.gcom | 33 + .../files/usr/lib/rooter/gcom/cellinfo.gcom | 50 + .../files/usr/lib/rooter/gcom/cellinfo0.gcom | 45 + .../files/usr/lib/rooter/gcom/cgpaddr.gcom | 46 + .../usr/lib/rooter/gcom/connect-directip.gcom | 64 + .../usr/lib/rooter/gcom/connect-fecm.gcom | 45 + .../usr/lib/rooter/gcom/connect-ncm.gcom | 48 + .../usr/lib/rooter/gcom/connect-ppp.gcom | 36 + .../usr/lib/rooter/gcom/connect-zecm.gcom | 45 + .../files/usr/lib/rooter/gcom/curc.gcom | 31 + .../usr/lib/rooter/gcom/fibocominfo.gcom | 65 + .../files/usr/lib/rooter/gcom/gcom-locked | 41 + .../files/usr/lib/rooter/gcom/gettype.gcom | 43 + .../files/usr/lib/rooter/gcom/huaweiinfo.gcom | 74 + .../files/usr/lib/rooter/gcom/lock-prov.gcom | 38 + .../usr/lib/rooter/gcom/mdm9215info.gcom | 43 + .../files/usr/lib/rooter/gcom/meiginfo.gcom | 69 + .../usr/lib/rooter/gcom/novatelinfo.gcom | 48 + .../files/usr/lib/rooter/gcom/otherinfo.gcom | 28 + .../files/usr/lib/rooter/gcom/quantainfo.gcom | 38 + .../usr/lib/rooter/gcom/quectelinfo.gcom | 76 + .../files/usr/lib/rooter/gcom/raw-ip.gcom | 31 + .../files/usr/lib/rooter/gcom/reset.gcom | 25 + .../files/usr/lib/rooter/gcom/run-at.gcom | 31 + .../files/usr/lib/rooter/gcom/sendsms-at.gcom | 45 + .../files/usr/lib/rooter/gcom/setapn.gcom | 45 + .../files/usr/lib/rooter/gcom/setpin.gcom | 53 + .../files/usr/lib/rooter/gcom/sierrainfo.gcom | 68 + .../files/usr/lib/rooter/gcom/simcominfo.gcom | 48 + .../files/usr/lib/rooter/gcom/smschk.gcom | 36 + .../files/usr/lib/rooter/gcom/smswrite.gcom | 39 + .../files/usr/lib/rooter/gcom/t77info.gcom | 70 + .../files/usr/lib/rooter/gcom/telitinfo.gcom | 48 + .../usr/lib/rooter/gcom/telitinfoln.gcom | 43 + .../files/usr/lib/rooter/gcom/ubloxinfo.gcom | 43 + .../files/usr/lib/rooter/gcom/ussd.gcom | 29 + .../files/usr/lib/rooter/gcom/zteinfo.gcom | 58 + .../files/usr/lib/rooter/gpio-set.sh | 23 + .../files/usr/lib/rooter/gpiomodel.lua | 221 ++ .../files/usr/lib/rooter/idown.lua | 22 + .../files/usr/lib/rooter/initialize.sh | 295 ++ .../files/usr/lib/rooter/log/at-logger | 12 + .../files/usr/lib/rooter/log/logger | 17 + .../files/usr/lib/rooter/log/modlogger.sh | 26 + .../files/usr/lib/rooter/log/mrotate.lua | 39 + .../files/usr/lib/rooter/log/rotate.lua | 43 + .../files/usr/lib/rooter/logprint.sh | 5 + .../files/usr/lib/rooter/luci/atcmd.sh | 21 + .../files/usr/lib/rooter/luci/celltype.sh | 495 +++ .../files/usr/lib/rooter/luci/em060-2xbands | 29 + .../files/usr/lib/rooter/luci/em12-2xbands | 46 + .../files/usr/lib/rooter/luci/em12-3xbands | 43 + .../files/usr/lib/rooter/luci/em20-2xbands | 50 + .../files/usr/lib/rooter/luci/em20-3xbands | 41 + .../files/usr/lib/rooter/luci/em20-4xbands | 8 + .../files/usr/lib/rooter/luci/em7411-2xbands | 29 + .../files/usr/lib/rooter/luci/em7411-3xbands | 8 + .../files/usr/lib/rooter/luci/em7511-2xbands | 60 + .../files/usr/lib/rooter/luci/em7511-3xbands | 55 + .../files/usr/lib/rooter/luci/em7565-2xbands | 14 + .../files/usr/lib/rooter/luci/em7565-3xbands | 51 + .../files/usr/lib/rooter/luci/ep06a-bands | 27 + .../files/usr/lib/rooter/luci/ep06e-bands | 32 + .../files/usr/lib/rooter/luci/l850-2xbands | 35 + .../files/usr/lib/rooter/luci/l850-3xbands | 27 + .../files/usr/lib/rooter/luci/lock.sh | 394 ++ .../files/usr/lib/rooter/luci/luaops.sh | 8 + .../files/usr/lib/rooter/luci/mask.sh | 332 ++ .../files/usr/lib/rooter/luci/mc7455-bands | 14 + .../files/usr/lib/rooter/luci/modechge.sh | 276 ++ .../files/usr/lib/rooter/luci/modemchge.sh | 46 + .../files/usr/lib/rooter/luci/portchge.sh | 28 + .../files/usr/lib/rooter/luci/protochnge.sh | 155 + .../files/usr/lib/rooter/luci/restart.sh | 53 + .../files/usr/lib/rooter/luci/scancmd.sh | 412 +++ .../files/usr/lib/rooter/luci/setcell.sh | 72 + .../files/usr/lib/rooter/luci/wifiradio.sh | 15 + .../files/usr/lib/rooter/mbimfind.lua | 92 + .../files/usr/lib/rooter/modeswitch.sh | 616 ++++ .../files/usr/lib/rooter/ncmfind.lua | 63 + .../files/usr/lib/rooter/nitz2sys.sh | 29 + .../files/usr/lib/rooter/portchge.sh | 28 + .../files/usr/lib/rooter/ppp/create_ppp.sh | 247 ++ .../files/usr/lib/rooter/protofind.lua | 254 ++ .../files/usr/lib/rooter/pwrtoggle.sh | 181 + .../files/usr/lib/rooter/shutall.sh | 14 + .../files/usr/lib/rooter/signal/basedata.sh | 79 + .../files/usr/lib/rooter/signal/celldata.sh | 136 + .../files/usr/lib/rooter/signal/celltype.lua | 142 + .../usr/lib/rooter/signal/huaweihostless.sh | 205 ++ .../files/usr/lib/rooter/signal/mccmnc.data | 11 + .../usr/lib/rooter/signal/modemsignal.sh | 287 ++ .../usr/lib/rooter/signal/otherhostless.sh | 160 + .../files/usr/lib/rooter/signal/status.sh | 46 + .../usr/lib/rooter/signal/ztehostless.sh | 215 ++ .../files/usr/lib/rooter/simlock.sh | 56 + .../files/usr/lib/rooter/simlockc.sh | 8 + .../files/usr/lib/rooter/sms/check_sms.sh | 32 + .../files/usr/lib/rooter/timezone.sh | 19 + .../files/usr/lib/rooter/tzone.lua | 478 +++ .../files/usr/lib/rooter/ussd.sh | 67 + rooter/ext-rooter-basic/files/usr/sbin/modlog | 7 + .../www/luci-static/background/main_bg.jpg | Bin 0 -> 134812 bytes .../files/www/luci-static/css/cascade.css | 3266 +++++++++++++++++ .../files/www/luci-static/css/dark.css | 1 + .../files/www/luci-static/css/fonts.css | 1 + .../files/www/luci-static/css/pure-min.css | 1 + .../fonts/Roboto-Medium-webfont.woff | Bin 0 -> 70200 bytes .../fonts/Roboto-Regular-webfont.woff | Bin 0 -> 68776 bytes .../www/luci-static/fonts/TypoGraphica.eot | Bin 0 -> 33846 bytes .../www/luci-static/fonts/TypoGraphica.svg | 1191 ++++++ .../www/luci-static/fonts/TypoGraphica.ttf | Bin 0 -> 33632 bytes .../www/luci-static/fonts/TypoGraphica.woff | Bin 0 -> 17816 bytes .../www/luci-static/fonts/advancedtomato.eot | Bin 0 -> 8480 bytes .../www/luci-static/fonts/advancedtomato.svg | 53 + .../www/luci-static/fonts/advancedtomato.ttf | Bin 0 -> 8288 bytes .../www/luci-static/fonts/advancedtomato.woff | Bin 0 -> 6272 bytes .../files/www/luci-static/fonts/argon.eot | Bin 0 -> 8888 bytes .../files/www/luci-static/fonts/argon.svg | 38 + .../files/www/luci-static/fonts/argon.ttf | Bin 0 -> 8732 bytes .../files/www/luci-static/fonts/argon.woff | Bin 0 -> 8808 bytes .../files/www/luci-static/fonts/font.eot | Bin 0 -> 1912 bytes .../files/www/luci-static/fonts/font.svg | 16 + .../files/www/luci-static/fonts/font.ttf | Bin 0 -> 1748 bytes .../files/www/luci-static/fonts/font.woff | Bin 0 -> 1824 bytes .../files/www/luci-static/fonts/fonts.css | 38 + .../luci-static/icon/android-icon-192x192.png | Bin 0 -> 6411 bytes .../luci-static/icon/apple-icon-144x144.png | Bin 0 -> 5222 bytes .../www/luci-static/icon/apple-icon-60x60.png | Bin 0 -> 2561 bytes .../www/luci-static/icon/apple-icon-72x72.png | Bin 0 -> 2877 bytes .../www/luci-static/icon/browserconfig.xml | 2 + .../www/luci-static/icon/favicon-16x16.png | Bin 0 -> 1019 bytes .../www/luci-static/icon/favicon-32x32.png | Bin 0 -> 1720 bytes .../www/luci-static/icon/favicon-96x96.png | Bin 0 -> 3650 bytes .../files/www/luci-static/icon/manifest.json | 41 + .../www/luci-static/icon/ms-icon-144x144.png | Bin 0 -> 5222 bytes .../files/www/luci-static/icons/arrow.svg | 1 + .../files/www/luci-static/icons/logout.svg | 1 + .../files/www/luci-static/icons/menu.svg | 1 + .../files/www/luci-static/icons/spinner.svg | 1 + .../files/www/luci-static/img/argon.svg | 61 + .../files/www/luci-static/img/blank.png | Bin 0 -> 938 bytes .../files/www/luci-static/img/open.png | Bin 0 -> 7603 bytes .../files/www/luci-static/img/volume_high.svg | 1 + .../files/www/luci-static/img/volume_off.svg | 1 + .../luci-static/resources/buttons/buttons.css | 702 ++++ .../www/luci-static/resources/icons/lock1.png | Bin 0 -> 13833 bytes .../luci-static/resources/icons/unlock1.png | Bin 0 -> 12460 bytes .../www/luci-static/resources/img/header.png | Bin 0 -> 4141 bytes .../www/luci-static/resources/img/rooter.png | Bin 0 -> 4644 bytes .../www/luci-static/resources/img/rosy.png | Bin 0 -> 19473 bytes 793 files changed, 76153 insertions(+) create mode 100644 rooter/0basicapps/ext-command/Makefile create mode 100644 rooter/0basicapps/ext-command/files/usr/lib/lua/luci/controller/commands.lua create mode 100644 rooter/0basicapps/ext-command/files/usr/lib/lua/luci/model/cbi/commands.lua create mode 100644 rooter/0basicapps/ext-command/files/usr/lib/lua/luci/view/cmdedit.htm create mode 100644 rooter/0basicapps/ext-command/files/usr/lib/lua/luci/view/commands.htm create mode 100644 rooter/0basicapps/ext-command/files/usr/lib/scripts/dummy create mode 100644 rooter/0basicapps/ext-extra/Makefile create mode 100644 rooter/0basicapps/ext-extra/files/etc/config/schedule create mode 100644 rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/controller/schedule.lua create mode 100644 rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/model/cbi/admin_system/cronnew.lua create mode 100644 rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/model/cbi/schedule.lua create mode 100644 rooter/0basicapps/ext-extra/files/usr/lib/rooter/luci/croncat.sh create mode 100644 rooter/0basicapps/ext-extra/files/usr/lib/rooter/luci/reboot.sh create mode 100644 rooter/0basicapps/ext-p910nd/Makefile create mode 100644 rooter/0basicapps/ext-p910nd/files/etc/uci-defaults/40_luci-p910ndx create mode 100644 rooter/0basicapps/ext-p910nd/files/usr/lib/lua/luci/controller/p910ndx.lua create mode 100644 rooter/0basicapps/ext-p910nd/files/usr/lib/lua/luci/model/cbi/p910ndx.lua create mode 100644 rooter/0basicapps/usb-storage/Makefile create mode 100644 rooter/0basicapps/usb-storage/files/etc/config/umount create mode 100644 rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/20-mount create mode 100644 rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/30-mount create mode 100644 rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/99-mount create mode 100644 rooter/0basicapps/usb-storage/files/etc/uci-defaults/40_luci-hd_idle create mode 100644 rooter/0basicapps/usb-storage/files/etc/umount create mode 100644 rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/controller/hd_idle.lua create mode 100644 rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/controller/umount.lua create mode 100644 rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/model/cbi/hd_idle.lua create mode 100644 rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/model/cbi/umount.lua create mode 100644 rooter/0basicapps/usb-storage/files/usr/lib/sdcard/sdcard.sh create mode 100644 rooter/0basicsupport/ext-buttons/Makefile create mode 100644 rooter/0basicsupport/ext-buttons/files/etc/btnaction.sh create mode 100644 rooter/0basicsupport/ext-buttons/files/etc/hotplug.d/button/00-button create mode 100644 rooter/0basicsupport/ext-buttons/files/etc/hotplug.d/button/10-buttonchk create mode 100644 rooter/0basicsupport/ext-buttons/files/etc/init.d/buttons create mode 100644 rooter/0basicsupport/ext-buttons/files/usr/lib/lua/luci/controller/buttons.lua create mode 100644 rooter/0basicsupport/ext-buttons/files/usr/lib/lua/luci/model/cbi/buttons/buttons.lua create mode 100644 rooter/0basicsupport/ext-sms/Makefile create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/lua/luci/controller/sms.lua create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/lua/luci/view/rooter/sms.htm create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/delsms.sh create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/pack7bit.lua create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/processsms create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/sendsms.lua create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/sendsms.sh create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsout.lua create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsout.sh create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsread.lua create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/sys2sms.lua create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/sys2sms.sh create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/toggle.sh create mode 100644 rooter/0basicsupport/ext-sms/files/usr/lib/sms/utf8togsm.lua create mode 100644 rooter/0basicsupport/luci-app-guestwifi/Makefile create mode 100644 rooter/0basicsupport/luci-app-guestwifi/files/etc/config/guestwifi create mode 100644 rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/create.sh create mode 100644 rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/remove.sh create mode 100644 rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/start.sh create mode 100644 rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/stop.sh create mode 100644 rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/controller/guestwifi.lua create mode 100644 rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/model/cbi/guestwifi-edit.lua create mode 100644 rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/model/cbi/guestwifi.lua create mode 100644 rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/view/guestwifi/cbi-select-input-add.htm create mode 100644 rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/view/guestwifi/ovpn_css.htm create mode 100644 rooter/0drivers/rmbim/.svn/entries create mode 100644 rooter/0drivers/rmbim/.svn/text-base/Makefile.svn-base create mode 100644 rooter/0drivers/rmbim/Makefile create mode 100644 rooter/0drivers/rmbim/files/lib/netifd/proto/mbim.sh create mode 100644 rooter/0drivers/rmbim/files/usr/lib/rooter/mbim/mbimdata.sh create mode 100644 rooter/0drivers/rmbim/files/usr/lib/rooter/mbim/monitor.sh create mode 100644 rooter/0drivers/rqmi/Makefile create mode 100644 rooter/0drivers/rqmi/files/usr/lib/rooter/qmi/connectqmi.sh create mode 100644 rooter/0mesh/mesh-mesh/Makefile create mode 100644 rooter/0mesh/mesh-mesh/files/etc/config/batman-adv create mode 100644 rooter/0mesh/mesh-mesh/files/etc/config/mesh create mode 100644 rooter/0mesh/mesh-mesh/files/etc/hotplug.d/net/99-batman-gw create mode 100644 rooter/0mesh/mesh-mesh/files/etc/init.d/zmesh create mode 100644 rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/controller/batman.lua create mode 100644 rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/controller/mesh.lua create mode 100644 rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/view/batman/batman.htm create mode 100644 rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/view/mesh/mesh-setup.htm create mode 100644 rooter/0mesh/mesh-mesh/files/usr/lib/mesh/checker.sh create mode 100644 rooter/0mesh/mesh-mesh/files/usr/lib/mesh/ping.sh create mode 100644 rooter/0mesh/mesh-mesh/files/usr/lib/mesh/radio.sh create mode 100644 rooter/0mesh/mesh-mesh/files/usr/lib/mesh/save.sh create mode 100644 rooter/0mesh/mesh-mesh/files/usr/lib/mesh/savecfg.sh create mode 100644 rooter/0mesh/mesh-mesh/files/usr/lib/mesh/startstop.sh create mode 100644 rooter/0mesh/mesh-mesh/files/www/luci-static/resources/dracula/dracula_graffle.js create mode 100644 rooter/0mesh/mesh-mesh/files/www/luci-static/resources/dracula/dracula_graph.js create mode 100644 rooter/0mesh/mesh-mesh/files/www/luci-static/resources/dracula/raphael-min.js create mode 100644 rooter/0mesh/mesh-mesh/files/www/luci-static/resources/jquery/jquery-1.4.js create mode 100644 rooter/0mesh/mesh-mesh/files/www/luci-static/resources/protocol/batadv.js create mode 100644 rooter/0mesh/mesh-mesh/files/www/luci-static/resources/protocol/batadv_hardif.js create mode 100644 rooter/0mesh/mesh-wpad/Makefile create mode 100644 rooter/0optionalapps/bwallocate/Makefile create mode 100644 rooter/0optionalapps/bwallocate/files/etc/init.d/textbwint create mode 100644 rooter/0optionalapps/bwallocate/files/usr/lib/lua/luci/controller/bwallocate.lua create mode 100644 rooter/0optionalapps/bwallocate/files/usr/lib/lua/luci/model/cbi/fullmenu/bwmenu.lua create mode 100644 rooter/0optionalapps/bwmon/Makefile create mode 100644 rooter/0optionalapps/bwmon/files/etc/config/bwmon create mode 100644 rooter/0optionalapps/bwmon/files/etc/init.d/bwmon create mode 100644 rooter/0optionalapps/bwmon/files/lib/upgrade/keep.d/bwmon create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/allocate.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/amtleft.lua create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup-daily.lua create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup-mon.lua create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/block create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/change.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/chksms.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/cleanup.lua create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/create.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/create_data.lua create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/data/placeholder create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/datainc.lua create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/dataper.lua create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/dotext.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/editemail.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/excede.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/external.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/float.lua create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/message create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/msmtprc create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/perday.lua create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/process.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/rollover.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/savetot.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/sendsms.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/textbw.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/bwmon/wrtbwmon.sh create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/lua/luci/controller/bwmon.lua create mode 100644 rooter/0optionalapps/bwmon/files/usr/lib/lua/luci/view/bwmon/bwmon.htm create mode 100644 rooter/0optionalapps/bwmon/files/usr/sbin/readDB.awk create mode 100644 rooter/0optionalapps/ext-autoapn/Makefile create mode 100644 rooter/0optionalapps/ext-autoapn/files/usr/lib/autoapn/apn.data create mode 100644 rooter/0optionalapps/ext-blacklist/Makefile create mode 100644 rooter/0optionalapps/ext-blacklist/files/etc/config/blacklist create mode 100644 rooter/0optionalapps/ext-blacklist/files/usr/lib/blacklist/blacklist.sh create mode 100644 rooter/0optionalapps/ext-blacklist/files/usr/lib/blacklist/chkblack.sh create mode 100644 rooter/0optionalapps/ext-blacklist/files/usr/lib/lua/luci/controller/blacklist.lua create mode 100644 rooter/0optionalapps/ext-blacklist/files/usr/lib/lua/luci/model/cbi/blacklist.lua create mode 100644 rooter/0optionalapps/ext-blockport/Makefile create mode 100644 rooter/0optionalapps/ext-blockport/files/etc/config/blockport create mode 100644 rooter/0optionalapps/ext-blockport/files/usr/lib/blockport/blockport.sh create mode 100644 rooter/0optionalapps/ext-blockport/files/usr/lib/lua/luci/controller/blockport.lua create mode 100644 rooter/0optionalapps/ext-blockport/files/usr/lib/lua/luci/model/cbi/portblk.lua create mode 100644 rooter/0optionalapps/ext-domain/Makefile create mode 100644 rooter/0optionalapps/ext-domain/files/etc/config/filter create mode 100644 rooter/0optionalapps/ext-domain/files/etc/init.d/domain create mode 100644 rooter/0optionalapps/ext-domain/files/usr/lib/domain/filter.sh create mode 100644 rooter/0optionalapps/ext-domain/files/usr/lib/lua/luci/controller/domain.lua create mode 100644 rooter/0optionalapps/ext-domain/files/usr/lib/lua/luci/model/cbi/domainfltr.lua create mode 100644 rooter/0optionalapps/ext-menu/Makefile create mode 100644 rooter/0optionalapps/ext-menu/files/etc/uci-defaults/63-menu create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/firewall.lua create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/luci-mod-status.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/luci-mod-system.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/network.lua create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/opkg.lua create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-app-firewall.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-app-opkg.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-network.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-status.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-system.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/firewall.lua create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/luci-mod-status.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/luci-mod-system.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/network.lua create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/opkg.lua create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-app-firewall.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-network.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-status.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-system.json create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/setmenu.sh create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/lua/luci/controller/fullmenu.lua create mode 100644 rooter/0optionalapps/ext-menu/files/usr/lib/lua/luci/view/fullmenu/fullmenu.htm create mode 100644 rooter/0optionalapps/ext-rspeedtest/Makefile create mode 100644 rooter/0optionalapps/ext-rspeedtest/files/usr/lib/lua/luci/controller/rspeedtest.lua create mode 100644 rooter/0optionalapps/ext-rspeedtest/files/usr/lib/lua/luci/view/speedtest/rspeedtest.htm create mode 100644 rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/closest.lua create mode 100644 rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/getspeed.sh create mode 100644 rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/info.sh create mode 100644 rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/ping.sh create mode 100644 rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/servers.lua create mode 100644 rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/stop.sh create mode 100644 rooter/0optionalapps/ext-rspeedtest/files/www/luci-static/resources/img/prov.png create mode 100644 rooter/0optionalapps/ext-rspeedtest/files/www/luci-static/resources/img/user.png create mode 100644 rooter/0optionalapps/ext-speedtest/Makefile create mode 100644 rooter/0optionalapps/ext-speedtest/files/usr/lib/lua/luci/controller/speedtest.lua create mode 100644 rooter/0optionalapps/ext-speedtest/files/usr/lib/lua/luci/view/speedtest/speedtest.htm create mode 100644 rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/css/iconmoon_splash.css create mode 100644 rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/css/splash.css create mode 100644 rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.eot create mode 100644 rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.svg create mode 100644 rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.ttf create mode 100644 rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.woff create mode 100644 rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/img/favicon.gif create mode 100644 rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/img/kangaroo_800.png create mode 100644 rooter/0optionalapps/ext-texting/Makefile create mode 100644 rooter/0optionalapps/ext-texting/files/etc/config/texting create mode 100644 rooter/0optionalapps/ext-texting/files/etc/init.d/texting create mode 100644 rooter/0optionalapps/ext-texting/files/usr/lib/fullmenu/chksms.sh create mode 100644 rooter/0optionalapps/ext-texting/files/usr/lib/fullmenu/dotext.sh create mode 100644 rooter/0optionalapps/ext-texting/files/usr/lib/fullmenu/text-setup.sh create mode 100644 rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/controller/texting.lua create mode 100644 rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/model/cbi/fullmenu/texting.lua create mode 100644 rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/view/fullmenu/textarea.htm create mode 100644 rooter/0optionalapps/ext-throttle/Makefile create mode 100644 rooter/0optionalapps/ext-throttle/files/etc/config/sqm create mode 100644 rooter/0optionalapps/ext-throttle/files/etc/hotplug.d/iface/11-sqm create mode 100644 rooter/0optionalapps/ext-throttle/files/etc/init.d/sqm create mode 100644 rooter/0optionalapps/ext-throttle/files/etc/sqm/sqm.conf create mode 100644 rooter/0optionalapps/ext-throttle/files/etc/uci-defaults/50-luci-sqm create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/defaults.sh create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/functions.sh create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/layer_cake.qos create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/layer_cake.qos.help create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/piece_of_cake.qos create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/piece_of_cake.qos.help create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/run.sh create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simple.qos create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simple.qos.help create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest.qos create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest.qos.help create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest_tbf.qos create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest_tbf.qos.help create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/start-sqm create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/stop-sqm create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/update-available-qdiscs create mode 100644 rooter/0optionalapps/ext-throttle/files/usr/lib/throttle/throttle.sh create mode 100644 rooter/0optionalapps/ext-wireguard/Makefile create mode 100644 rooter/0optionalapps/ext-wireguard/files/etc/config/wireguard create mode 100644 rooter/0optionalapps/ext-wireguard/files/etc/config/wireguard_recipes create mode 100644 rooter/0optionalapps/ext-wireguard/files/etc/init.d/wireguard create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/controller/wireguard.lua create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard-client.lua create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard-server.lua create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard.lua create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/cbi-select-input-add.htm create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/conf.htm create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/ovpn_css.htm create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/pageswitch.htm create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/text_conf.htm create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/wireguard.htm create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/conf.sh create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/create.sh create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/keygen.sh create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/startvpn.sh create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/stopvpn.sh create mode 100644 rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/text.sh create mode 100644 rooter/0optionalapps/ext-wireguard/files/www/luci-static/resources/icons/wireguard.png create mode 100644 rooter/0optionalapps/ext-wireguard/files/www/luci-static/resources/icons/wireguard_disabled.png create mode 100644 rooter/0optionalapps/ext-zerotier/Makefile create mode 100644 rooter/0optionalapps/ext-zerotier/files/etc/init.d/zerofire create mode 100644 rooter/0optionalapps/ext-zerotier/files/etc/uci-defaults/64-zerotier create mode 100644 rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/controller/zerotier.lua create mode 100644 rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/admin_status/index/zero.htm create mode 100644 rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/zerotier/zerotier.htm create mode 100644 rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/zerotier/zerotier1.htm create mode 100644 rooter/0optionalapps/ext-zerotier/files/usr/lib/zerotier/netid.sh create mode 100644 rooter/0optionalapps/extramenu/Makefile create mode 100644 rooter/0optionalapps/extramenu/files/etc/init.d/fullmenu create mode 100644 rooter/0optionalapps/extramenu/files/usr/lib/fullmenu/setmenu.sh create mode 100644 rooter/0optionalapps/extramenu/files/usr/lib/lua/luci/controller/fullmenu.lua create mode 100644 rooter/0optionalapps/extramenu/files/usr/lib/lua/luci/view/fullmenu/fullmenu.htm create mode 100644 rooter/0optionalapps/libmicroxml/Makefile create mode 100644 rooter/0optionalapps/luci-app-dnsmasq-ipset/Makefile create mode 100644 rooter/0optionalapps/luci-app-dnsmasq-ipset/files/etc/config/dnsmasq-ipset create mode 100644 rooter/0optionalapps/luci-app-dnsmasq-ipset/files/etc/init.d/dnsmasq-ipset create mode 100644 rooter/0optionalapps/luci-app-dnsmasq-ipset/files/usr/lib/lua/luci/controller/dnsmasq-ipset.lua create mode 100644 rooter/0optionalapps/luci-app-dnsmasq-ipset/files/usr/lib/lua/luci/model/cbi/dnsmasq-ipset.lua create mode 100644 rooter/0optionalapps/luci-app-hotspot/Makefile create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/etc/config/travelmate create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/etc/hotplug.d/iface/99-travelmate-iface create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/etc/init.d/travelmate create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/etc/init.d/zhot create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/lib/upgrade/keep.d/hotspot create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/bin/hkillall create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/band.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/copyhot.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/dis_hot.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/enable.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/getssid.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/inrange.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/manual.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/mode.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/reconn.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/travelmate.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/controller/hotspot.lua create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/controller/wifilog.lua create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/view/hotspot/hotspot.htm create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/view/wifilog/wifilog.htm create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/lib/rooter/log/wifilogger.sh create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/usr/sbin/wifilog create mode 100644 rooter/0optionalapps/luci-app-hotspot/files/www/luci-static/resources/icons/encryption.png create mode 100644 rooter/0optionalapps/luci-app-iperf/Makefile create mode 100644 rooter/0optionalapps/luci-app-iperf/files/etc/config/iperf create mode 100644 rooter/0optionalapps/luci-app-iperf/files/usr/lib/lua/luci/controller/iperf.lua create mode 100644 rooter/0optionalapps/luci-app-iperf/files/usr/lib/lua/luci/view/iperf/test.htm create mode 100644 rooter/0optionalapps/luci-app-iperf/files/usr/share/luci/menu.d/luci-app-iperf.json create mode 100644 rooter/0optionalapps/luci-app-iperf/files/usr/share/rpcd/acl.d/luci-app-iperf.json create mode 100644 rooter/0optionalapps/luci-app-rootervpn/Makefile create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/config/openvpn_recipes create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/init.d/openvpn create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/init.d/rootervpn create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/ca.crt create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/client.crt create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/client.key create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/ta.key create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/mullvad/mullvad_ca.crt create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/mullvad/mullvad_crl.pem create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/pia/ca.rsa.2048.crt create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/pia/crl.rsa.2048.pem create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/placeholder/placeholder.file create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/windscribe/ca.crt create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/windscribe/ta.key create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/lib/upgrade/keep.d/rootervpn create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/bin/ovpn-userpass create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/bin/rkillall create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/dns.sh create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/firewall.sh create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/generate.sh create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/stop.sh create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/vpn.sh create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/vpng.sh create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/controller/openvpn.lua create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-advanced.lua create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-basic.lua create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-file.lua create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-server.lua create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn.lua create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/admin_status/index/vpn.htm create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/easyrsa/easyrsa.htm create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/cbi-select-input-add.htm create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/ovpn_css.htm create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/pageswitch.htm create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/vpn1.htm create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/www/luci-static/resources/icons/vpn-disabled.png create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/www/luci-static/resources/icons/vpn-started.png create mode 100644 rooter/0optionalapps/luci-app-rootervpn/files/www/luci-static/resources/icons/vpn-stopped.png create mode 100644 rooter/0optionalapps/pingtest/Makefile create mode 100644 rooter/0optionalapps/pingtest/files/usr/lib/custom/johns_ping.sh create mode 100644 rooter/0optionalapps/pingtest/files/usr/lib/custom/test_ping.sh create mode 100644 rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/controller/ping.lua create mode 100644 rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/model/cbi/ping.lua create mode 100644 rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/view/admin_status/index/extping.htm create mode 100644 rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/view/pingtest/extping.htm create mode 100644 rooter/0optionalapps/qfirehose/Makefile create mode 100644 rooter/0optionalapps/qfirehose/src/Makefile create mode 100644 rooter/0optionalapps/qfirehose/src/firehose_protocol.c create mode 100644 rooter/0optionalapps/qfirehose/src/hostdl_packet.h create mode 100644 rooter/0optionalapps/qfirehose/src/md5.c create mode 100644 rooter/0optionalapps/qfirehose/src/md5.h create mode 100644 rooter/0optionalapps/qfirehose/src/qfirehose.c create mode 100644 rooter/0optionalapps/qfirehose/src/sahara_protocol.c create mode 100644 rooter/0optionalapps/qfirehose/src/sahara_protocol.h create mode 100644 rooter/0optionalapps/qfirehose/src/stream_download_protocol.c create mode 100644 rooter/0optionalapps/qfirehose/src/usb2tcp.c create mode 100644 rooter/0optionalapps/qfirehose/src/usb_linux.c create mode 100644 rooter/0optionalapps/qfirehose/src/usb_linux.h create mode 100644 rooter/0optionalapps/qlog/Makefile create mode 100644 rooter/0optionalapps/qlog/files/usr/lib/conf/T1.LinuxData-OTA-DataService-AP_V01.cfg create mode 100644 rooter/0optionalapps/qlog/files/usr/lib/conf/T2.RegServ-CotextAct_V01.cfg create mode 100644 rooter/0optionalapps/qlog/files/usr/lib/conf/T3.SimpleData-(TCPUDP)_V01.cfg create mode 100644 rooter/0optionalapps/qlog/files/usr/lib/conf/T4.Throughput_V01.cfg create mode 100644 rooter/0optionalapps/qlog/files/usr/lib/conf/T5.COMMON-T1T4_V01.cfg create mode 100644 rooter/0optionalapps/qlog/files/usr/lib/conf/T6.FullMessage.SimpleLogPacket(AT)_V01.cfg create mode 100644 rooter/0optionalapps/qlog/files/usr/lib/conf/T7.V2X_ALL_V01.cfg create mode 100644 rooter/0optionalapps/qlog/files/usr/lib/conf/default.cfg create mode 100644 rooter/0optionalapps/qlog/src/Makefile create mode 100644 rooter/0optionalapps/qlog/src/asr.c create mode 100644 rooter/0optionalapps/qlog/src/main.c create mode 100644 rooter/0optionalapps/qlog/src/mdm.c create mode 100644 rooter/0optionalapps/qlog/src/qlog.h create mode 100644 rooter/0optionalapps/qlog/src/sahara.c create mode 100644 rooter/0optionalapps/qlog/src/sahara_protocol.h create mode 100644 rooter/0optionalapps/qlog/src/tty2tcp.c create mode 100644 rooter/0optionalapps/udp-tunnel/Makefile create mode 100644 rooter/0optionalapps/udp-tunnel/src/Makefile create mode 100644 rooter/0optionalapps/udp-tunnel/src/log.c create mode 100644 rooter/0optionalapps/udp-tunnel/src/log.h create mode 100644 rooter/0optionalapps/udp-tunnel/src/network.c create mode 100644 rooter/0optionalapps/udp-tunnel/src/network.h create mode 100644 rooter/0optionalapps/udp-tunnel/src/udptunnel.c create mode 100644 rooter/0optionalapps/udp-tunnel/src/utils.c create mode 100644 rooter/0optionalapps/udp-tunnel/src/utils.h create mode 100644 rooter/0optionalapps/webconsole/Makefile create mode 100644 rooter/0optionalapps/webconsole/files/usr/lib/lua/luci/controller/webconsole.lua create mode 100644 rooter/0optionalapps/webconsole/files/usr/lib/lua/luci/view/web/web_console.htm create mode 100644 rooter/0protocols/luci-proto-3x/Makefile create mode 100644 rooter/0protocols/luci-proto-3x/files/usr/lib/lua/luci/model/cbi/admin_network/proto_3x.lua create mode 100644 rooter/0protocols/luci-proto-3x/files/usr/lib/lua/luci/model/network/proto_3x.lua create mode 100644 rooter/0protocols/luci-proto-3x/files/www/luci-static/resources/protocol/3x.js create mode 100644 rooter/0protocols/luci-proto-mbim/Makefile create mode 100644 rooter/0protocols/luci-proto-mbim/files/usr/lib/lua/luci/model/cbi/admin_network/proto_mbim.lua create mode 100644 rooter/0protocols/luci-proto-mbim/files/usr/lib/lua/luci/model/network/proto_mbim.lua create mode 100644 rooter/0protocols/luci-proto-mbim/files/www/luci-static/resources/protocol/mbim.js create mode 100644 rooter/0routerspecfic/alix2d13/Makefile create mode 100644 rooter/0routerspecfic/alix2d13/files/usr/lib/rooter/special.sh create mode 100644 rooter/0routerspecfic/apu2c4/Makefile create mode 100644 rooter/0routerspecfic/b1300/Makefile create mode 100644 rooter/0routerspecfic/b1300/files/usr/lib/rooter/special.sh create mode 100644 rooter/0routerspecfic/d240/Makefile create mode 100644 rooter/0routerspecfic/d240/files/usr/lib/sdcard/sdcard.sh create mode 100644 rooter/0routerspecfic/dir860l/Makefile create mode 100644 rooter/0routerspecfic/dir860l/files/etc/hotplug.d/iface/99-dir860-led create mode 100644 rooter/0routerspecfic/dir860l/files/usr/lib/rooter/special.sh create mode 100644 rooter/0routerspecfic/ext-ssh/Makefile create mode 100644 rooter/0routerspecfic/ext-ssh/files/etc/init.d/sshd create mode 100644 rooter/0routerspecfic/ext-ssh/files/etc/ssh/moduli create mode 100644 rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_config create mode 100644 rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ecdsa_key create mode 100644 rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ecdsa_key.pub create mode 100644 rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ed25519_key create mode 100644 rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ed25519_key.pub create mode 100644 rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_rsa_key create mode 100644 rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_rsa_key.pub create mode 100644 rooter/0routerspecfic/ext-ssh/files/etc/ssh/sshd_config create mode 100644 rooter/0routerspecfic/fscheck/Makefile create mode 100644 rooter/0routerspecfic/fscheck/files/usr/lib/lua/luci/controller/filecheck.lua create mode 100644 rooter/0routerspecfic/fscheck/files/usr/lib/lua/luci/view/admin_system/filecheck.htm create mode 100644 rooter/0routerspecfic/fscheck/files/usr/lib/rooter/filecheck.sh create mode 100644 rooter/0routerspecfic/h721/Makefile create mode 100644 rooter/0routerspecfic/h721/files/etc/exportgpio.sh create mode 100644 rooter/0routerspecfic/h721/files/etc/init.d/custom create mode 100644 rooter/0routerspecfic/h721/files/etc/init.d/exportgpio create mode 100644 rooter/0routerspecfic/h721/files/usr/lib/custom/custom.lua create mode 100644 rooter/0routerspecfic/h721/files/usr/lib/custom/hostname.sh create mode 100644 rooter/0routerspecfic/h721/files/usr/lib/custom/wifi.sh create mode 100644 rooter/0routerspecfic/h721/files/usr/lib/rooter/modem-led.sh create mode 100644 rooter/0routerspecfic/h721/files/usr/lib/rooter/special.sh create mode 100644 rooter/0routerspecfic/mt1300/Makefile create mode 100644 rooter/0routerspecfic/mt1300/files/etc/init.d/mt1300 create mode 100644 rooter/0routerspecfic/rbm11g/Makefile create mode 100644 rooter/0routerspecfic/rbm11g/files/usr/lib/rooter/modem-led.sh create mode 100644 rooter/0routerspecfic/rbm11g/files/usr/lib/rooter/special.sh create mode 100644 rooter/0routerspecfic/rbm33g/Makefile create mode 100644 rooter/0routerspecfic/rbm33g/files/usr/lib/rooter/special.sh create mode 100644 rooter/0routerspecfic/rbsxtr/Makefile create mode 100644 rooter/0routerspecfic/rbsxtr/files/etc/uci-defaults/40_luci-theme create mode 100644 rooter/0routerspecfic/rbsxtr/files/usr/lib/rooter/modem-led.sh create mode 100644 rooter/0routerspecfic/rbsxtr/files/www/luci-static/background/main_bg.jpg create mode 100644 rooter/0routerspecfic/rbsxtr/files/www/luci-static/img/open.png create mode 100644 rooter/0routerspecfic/rd05a1/Makefile create mode 100644 rooter/0routerspecfic/rd05a1/files/etc/init.d/pciepwr create mode 100644 rooter/0routerspecfic/vpnpolicy/Makefile create mode 100644 rooter/0routerspecfic/we826/Makefile create mode 100644 rooter/0routerspecfic/we826/files/etc/init.d/wd-init create mode 100644 rooter/0routerspecfic/we826/files/usr/lib/custom/watchdog.sh create mode 100644 rooter/0routerspecfic/we826q/Makefile create mode 100644 rooter/0routerspecfic/we826q/files/etc/init.d/wd-init create mode 100644 rooter/0routerspecfic/we826q/files/usr/lib/custom/watchdog.sh create mode 100644 rooter/0routerspecfic/wg1602/Makefile create mode 100644 rooter/0routerspecfic/wg1602/files/etc/init.d/sw-init create mode 100644 rooter/0routerspecfic/wg1602/files/usr/lib/rooter/special.sh create mode 100644 rooter/0routerspecfic/wg1608/Makefile create mode 100644 rooter/0routerspecfic/wg1608/files/etc/init.d/wd-init create mode 100644 rooter/0routerspecfic/wg1608/files/usr/lib/custom/watchdog.sh create mode 100644 rooter/0routerspecfic/wg1608/files/usr/lib/rooter/modem-led.sh create mode 100644 rooter/0routerspecfic/wg1608/files/usr/lib/rooter/special.sh create mode 100644 rooter/0routerspecfic/wg209/Makefile create mode 100644 rooter/0routerspecfic/wg209/files/usr/lib/rooter/modem-led.sh create mode 100644 rooter/0routerspecfic/wg259/Makefile create mode 100644 rooter/0routerspecfic/wg259/files/usr/lib/rooter/special.sh create mode 100644 rooter/0routerspecfic/wg3526/Makefile create mode 100644 rooter/0routerspecfic/wg3526/files/usr/lib/rooter/special.sh create mode 100644 rooter/0routerspecfic/wg827/Makefile create mode 100644 rooter/0routerspecfic/wg827/files/usr/lib/rooter/modem-led.sh create mode 100644 rooter/0routerspecfic/wrt1900/Makefile create mode 100644 rooter/0routerspecfic/wrt1900/files/etc/init.d/amsdu create mode 100644 rooter/0routerspecfic/x750/Makefile create mode 100644 rooter/0routerspecfic/x750/files/usr/lib/rooter/special.sh create mode 100644 rooter/0splash/ext-splash/Makefile create mode 100644 rooter/0splash/ext-splash/files/etc/config/iframe create mode 100644 rooter/0splash/ext-splash/files/etc/init.d/iframeint create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/band.html create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/bwdays.sh create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/bwtemplate.html create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/create.sh create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/daylist.html create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/iframe.html create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/image.html create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/modem2.html create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/open.html create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/speed.html create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/status.html create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/status.sh create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/stupdate.sh create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/update.sh create mode 100644 rooter/0splash/ext-splash/files/usr/lib/iframe/zerotier.html create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/display.html create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/iframe.html create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/ifstatus.html create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/rooter/css/iconmoon_splash.css create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/rooter/css/splash.css create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.eot create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.svg create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.ttf create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.woff create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/rooter/img/favicon.gif create mode 100644 rooter/0splash/ext-splash/files/www/luci-static/rooter/img/kangaroo_800.png create mode 100644 rooter/0splash/ext-splash/files/www/splash_files/check1.gif create mode 100644 rooter/0splash/ext-splashconfig/Makefile create mode 100644 rooter/0splash/ext-splashconfig/files/usr/lib/lua/luci/controller/splash.lua create mode 100644 rooter/0splash/ext-splashconfig/files/usr/lib/lua/luci/model/cbi/splashm.lua create mode 100644 rooter/0splash/splash/Makefile create mode 100644 rooter/0splash/splash/files/www/luci-static/rooter/css/iconmoon_splash.css create mode 100644 rooter/0splash/splash/files/www/luci-static/rooter/css/splash.css create mode 100644 rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.eot create mode 100644 rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.svg create mode 100644 rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.ttf create mode 100644 rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.woff create mode 100644 rooter/0splash/splash/files/www/luci-static/rooter/img/favicon.gif create mode 100644 rooter/0splash/splash/files/www/luci-static/rooter/img/kangaroo_800.png create mode 100644 rooter/0splash/splash/files/www/splash.html create mode 100644 rooter/0splash/splash/files/www/splash_files/cellular.png create mode 100644 rooter/0splash/splash/files/www/splash_files/check.gif create mode 100644 rooter/0splash/splash/files/www/splash_files/check.jpg create mode 100644 rooter/0splash/splash/files/www/splash_files/forum.png create mode 100644 rooter/0splash/splash/files/www/splash_files/home.png create mode 100644 rooter/0splash/splash/files/www/splash_files/kanga1.png create mode 100644 rooter/0splash/splash/files/www/splash_files/openwrt.png create mode 100644 rooter/0splash/splash/files/www/splash_files/rooter.png create mode 100644 rooter/0splash/splash/files/www/status.html create mode 100644 rooter/0splash/status/Makefile create mode 100644 rooter/0splash/status/files/etc/config/splash create mode 100644 rooter/0splash/status/files/usr/lib/lua/luci/controller/splashset.lua create mode 100644 rooter/0splash/status/files/usr/lib/lua/luci/model/cbi/splash.lua create mode 100644 rooter/0splash/status/files/usr/lib/splash/check.gif create mode 100644 rooter/0splash/status/files/usr/lib/splash/full.gif create mode 100644 rooter/0splash/status/files/usr/lib/splash/splash.sh create mode 100644 rooter/0splash/status/files/www/luci-static/rooter/css/iconmoon_splash.css create mode 100644 rooter/0splash/status/files/www/luci-static/rooter/css/splash.css create mode 100644 rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.eot create mode 100644 rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.svg create mode 100644 rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.ttf create mode 100644 rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.woff create mode 100644 rooter/0splash/status/files/www/luci-static/rooter/img/favicon.gif create mode 100644 rooter/0splash/status/files/www/luci-static/rooter/img/kangaroo_800.png create mode 100644 rooter/0splash/status/files/www/splash.html create mode 100644 rooter/0splash/status/files/www/splash_files/cellular.png create mode 100644 rooter/0splash/status/files/www/splash_files/check.jpg create mode 100644 rooter/0splash/status/files/www/splash_files/forum.png create mode 100644 rooter/0splash/status/files/www/splash_files/home.png create mode 100644 rooter/0splash/status/files/www/splash_files/kanga1.png create mode 100644 rooter/0splash/status/files/www/splash_files/openwrt.png create mode 100644 rooter/0splash/status/files/www/splash_files/rooter.png create mode 100644 rooter/0splash/status/files/www/splashfull.html create mode 100644 rooter/0splash/status/files/www/statusfull.html create mode 100644 rooter/ext-rooter-basic/Makefile create mode 100644 rooter/ext-rooter-basic/files/etc/codename create mode 100644 rooter/ext-rooter-basic/files/etc/config/custom create mode 100644 rooter/ext-rooter-basic/files/etc/config/modem create mode 100644 rooter/ext-rooter-basic/files/etc/config/profile create mode 100644 rooter/ext-rooter-basic/files/etc/config/ttl create mode 100644 rooter/ext-rooter-basic/files/etc/config/variable create mode 100644 rooter/ext-rooter-basic/files/etc/genericcmd create mode 100644 rooter/ext-rooter-basic/files/etc/header_msg create mode 100644 rooter/ext-rooter-basic/files/etc/hotplug.d/iface/10-lan create mode 100644 rooter/ext-rooter-basic/files/etc/hotplug.d/iface/19-rooter create mode 100644 rooter/ext-rooter-basic/files/etc/hotplug.d/tty/30-3x create mode 100644 rooter/ext-rooter-basic/files/etc/hotplug.d/usb/20-usb_mode create mode 100644 rooter/ext-rooter-basic/files/etc/init.d/clear create mode 100644 rooter/ext-rooter-basic/files/etc/init.d/iphone create mode 100644 rooter/ext-rooter-basic/files/etc/init.d/rooter create mode 100644 rooter/ext-rooter-basic/files/etc/init.d/usbmode create mode 100644 rooter/ext-rooter-basic/files/etc/lockdown/locks/0000000000000000000000000000000000000000.plist create mode 100644 rooter/ext-rooter-basic/files/etc/netspeed create mode 100644 rooter/ext-rooter-basic/files/etc/newstyle create mode 100644 rooter/ext-rooter-basic/files/etc/quectelcmd create mode 100644 rooter/ext-rooter-basic/files/etc/sierracmd create mode 100644 rooter/ext-rooter-basic/files/etc/ttl.user create mode 100644 rooter/ext-rooter-basic/files/etc/usb-mode.json create mode 100644 rooter/ext-rooter-basic/files/lib/netifd/proto/3x.sh create mode 100644 rooter/ext-rooter-basic/files/lib/upgrade/keep.d/cronfiles create mode 100644 rooter/ext-rooter-basic/files/lib/upgrade/keep.d/rc-local create mode 100644 rooter/ext-rooter-basic/files/usr/bin/bmask128 create mode 100644 rooter/ext-rooter-basic/files/usr/bin/chan2band.sh create mode 100644 rooter/ext-rooter-basic/files/usr/bin/encodemask create mode 100644 rooter/ext-rooter-basic/files/usr/bin/jkillall create mode 100644 rooter/ext-rooter-basic/files/usr/bin/rsrp2rssi create mode 100644 rooter/ext-rooter-basic/files/usr/bin/set_gpio create mode 100644 rooter/ext-rooter-basic/files/usr/lib/custom/locktype.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/custom/ttlx.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/gps/smsreply.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/admin/modem.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/modlog.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/poweroff.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/profile.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/firewall/ttlx.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/rooter/customize.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/rooter/profiles.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/admin_status/index/external.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/admin_system/poweroff.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/modlog/modlog.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/bandlock.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/custom.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/debug.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/external.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/log.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/misc.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/net_status.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/profile.htm create mode 100644 rooter/ext-rooter-basic/files/usr/lib/modlog/modlogger.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/profile/loadcfg.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/profile/restart.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/profile/savecfg.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/autoapn.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/cdmafind.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/chan2band.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/fibocomdata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/gettype.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/huaweidata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/lockchk.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/mdm9215data.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/meigdata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/modemchk.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/novateldata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/otherdata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/phone.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/processat.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/quantadata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/quecteldata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/sierradata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/simcomdata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/t77data.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/telitdata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/ubloxdata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/common/ztedata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/bandmask create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/conmon.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_connect.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_hostless.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_iphone.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/disablemw3.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/disconnect.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/get_profile.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/handlettl.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/postconnect.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/preconnect.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/reconnect-ppp.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/connect/reconnect.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/customname.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/auto.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/baseinfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cellinfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cellinfo0.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cgpaddr.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-directip.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-fecm.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-ncm.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-ppp.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-zecm.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/curc.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/fibocominfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/gcom-locked create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/gettype.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/huaweiinfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/lock-prov.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/mdm9215info.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/meiginfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/novatelinfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/otherinfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/quantainfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/quectelinfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/raw-ip.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/reset.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/run-at.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/sendsms-at.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/setapn.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/setpin.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/sierrainfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/simcominfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/smschk.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/smswrite.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/t77info.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/telitinfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/telitinfoln.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/ubloxinfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/ussd.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/zteinfo.gcom create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gpio-set.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/gpiomodel.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/idown.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/initialize.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/log/at-logger create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/log/logger create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/log/modlogger.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/log/mrotate.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/log/rotate.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/logprint.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/atcmd.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/celltype.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em060-2xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em12-2xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em12-3xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-2xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-3xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-4xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7411-2xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7411-3xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7511-2xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7511-3xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7565-2xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7565-3xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/ep06a-bands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/ep06e-bands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/l850-2xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/l850-3xbands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/lock.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/luaops.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/mask.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/mc7455-bands create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/modechge.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/modemchge.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/portchge.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/protochnge.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/restart.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/scancmd.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/setcell.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/luci/wifiradio.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/mbimfind.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/modeswitch.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/ncmfind.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/nitz2sys.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/portchge.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/ppp/create_ppp.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/protofind.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/pwrtoggle.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/shutall.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/signal/basedata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/signal/celldata.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/signal/celltype.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/signal/huaweihostless.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/signal/mccmnc.data create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/signal/modemsignal.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/signal/otherhostless.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/signal/status.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/signal/ztehostless.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/simlock.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/simlockc.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/sms/check_sms.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/timezone.sh create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/tzone.lua create mode 100644 rooter/ext-rooter-basic/files/usr/lib/rooter/ussd.sh create mode 100644 rooter/ext-rooter-basic/files/usr/sbin/modlog create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/background/main_bg.jpg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/css/cascade.css create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/css/dark.css create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/css/fonts.css create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/css/pure-min.css create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/Roboto-Medium-webfont.woff create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/Roboto-Regular-webfont.woff create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.eot create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.ttf create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.woff create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.eot create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.ttf create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.woff create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.eot create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.ttf create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.woff create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/font.eot create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/font.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/font.ttf create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/font.woff create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/fonts/fonts.css create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icon/android-icon-192x192.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icon/apple-icon-144x144.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icon/apple-icon-60x60.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icon/apple-icon-72x72.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icon/browserconfig.xml create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icon/favicon-16x16.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icon/favicon-32x32.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icon/favicon-96x96.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icon/manifest.json create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icon/ms-icon-144x144.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icons/arrow.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icons/logout.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icons/menu.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/icons/spinner.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/img/argon.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/img/blank.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/img/open.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/img/volume_high.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/img/volume_off.svg create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/resources/buttons/buttons.css create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/resources/icons/lock1.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/resources/icons/unlock1.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/resources/img/header.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/resources/img/rooter.png create mode 100644 rooter/ext-rooter-basic/files/www/luci-static/resources/img/rosy.png diff --git a/rooter/0basicapps/ext-command/Makefile b/rooter/0basicapps/ext-command/Makefile new file mode 100644 index 0000000..828e77a --- /dev/null +++ b/rooter/0basicapps/ext-command/Makefile @@ -0,0 +1,33 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-command +PKG_VERSION:=4.500 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-command + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Basic Applications + TITLE:=support for Command + PKGARCH:=all +endef + +define Package/ext-command/description + Helper scripts to enable command +endef + + +define Build/Compile +endef + +define Package/ext-command/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,ext-command)) diff --git a/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/controller/commands.lua b/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/controller/commands.lua new file mode 100644 index 0000000..a9f0640 --- /dev/null +++ b/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/controller/commands.lua @@ -0,0 +1,296 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2012 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +]]-- + +module("luci.controller.commands", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + entry({"admin", "system", "commands"}, firstchild(), _(translate("Custom Commands")), 80) + entry({"admin", "system", "commands", "dashboard"}, template("commands"), _(translate("Dashboard")), 1) + entry({"admin", "system", "commands", "config"}, cbi("commands"), _(translate("Configure")), 2) + entry({"admin", "system", "commands", "script"}, template("cmdedit"), _(translate("Scripts")), 3) + entry({"admin", "system", "commands", "run"}, call("action_run"), nil, 3).leaf = true + entry({"admin", "system", "commands", "download"}, call("action_download"), nil, 3).leaf = true + end + + entry({"admin", "system", "load_script"}, call("action_load_script")) + entry({"admin", "system", "save_script"}, call("action_save_script")) + entry({"admin", "system", "del_script"}, call("action_del_script")) + + entry({"command"}, call("action_public"), nil, 1).leaf = true +end + +--- Decode a given string into arguments following shell quoting rules +--- [[abc \def "foo\"bar" abc'def']] -> [[abc def]] [[foo"bar]] [[abcdef]] +local function parse_args(str) + local args = { } + + local function isspace(c) + if c == 9 or c == 10 or c == 11 or c == 12 or c == 13 or c == 32 then + return c + end + end + + local function isquote(c) + if c == 34 or c == 39 or c == 96 then + return c + end + end + + local function isescape(c) + if c == 92 then + return c + end + end + + local function ismeta(c) + if c == 36 or c == 92 or c == 96 then + return c + end + end + + --- Convert given table of byte values into a Lua string and append it to + --- the "args" table. Segment byte value sequence into chunks of 256 values + --- to not trip over the parameter limit for string.char() + local function putstr(bytes) + local chunks = { } + local csz = 256 + local upk = unpack + local chr = string.char + local min = math.min + local len = #bytes + local off + + for off = 1, len, csz do + chunks[#chunks+1] = chr(upk(bytes, off, min(off + csz - 1, len))) + end + + args[#args+1] = table.concat(chunks) + end + + --- Scan substring defined by the indexes [s, e] of the string "str", + --- perform unquoting and de-escaping on the fly and store the result in + --- a table of byte values which is passed to putstr() + local function unquote(s, e) + local off, esc, quote + local res = { } + + for off = s, e do + local byte = str:byte(off) + local q = isquote(byte) + local e = isescape(byte) + local m = ismeta(byte) + + if e then + esc = true + elseif esc then + if m then res[#res+1] = 92 end + res[#res+1] = byte + esc = false + elseif q and quote and q == quote then + quote = nil + elseif q and not quote then + quote = q + else + if m then res[#res+1] = 92 end + res[#res+1] = byte + end + end + + putstr(res) + end + + --- Find substring boundaries in "str". Ignore escaped or quoted + --- whitespace, pass found start- and end-index for each substring + --- to unquote() + local off, esc, start, quote + for off = 1, #str + 1 do + local byte = str:byte(off) + local q = isquote(byte) + local s = isspace(byte) or (off > #str) + local e = isescape(byte) + + if esc then + esc = false + elseif e then + esc = true + elseif q and quote and q == quote then + quote = nil + elseif q and not quote then + start = start or off + quote = q + elseif s and not quote then + if start then + unquote(start, off - 1) + start = nil + end + else + start = start or off + end + end + + --- If the "quote" is still set we encountered an unfinished string + if quote then + unquote(start, #str) + end + + return args +end + +local function parse_cmdline(cmdid, args) + local uci = require "luci.model.uci".cursor() + if uci:get("luci", cmdid) == "command" then + local cmd = uci:get_all("luci", cmdid) + local argv = parse_args(cmd.command) + local i, v + + if cmd.param == "1" and args then + for i, v in ipairs(parse_args(luci.http.urldecode(args))) do + argv[#argv+1] = v + end + end + + for i, v in ipairs(argv) do + if v:match("[^%w%.%-i/]") then + argv[i] = '"%s"' % v:gsub('"', '\\"') + end + end + + return argv + end +end + +function action_run(...) + local fs = require "nixio.fs" + local argv = parse_cmdline(...) + if argv then + local outfile = os.tmpname() + local errfile = os.tmpname() + + local rv = os.execute(table.concat(argv, " ") .. " >%s 2>%s" %{ outfile, errfile }) + local stdout = fs.readfile(outfile, 1024 * 512) or "" + local stderr = fs.readfile(errfile, 1024 * 512) or "" + + fs.unlink(outfile) + fs.unlink(errfile) + + local binary = not not (stdout:match("[%z\1-\8\14-\31]")) + + luci.http.prepare_content("application/json") + luci.http.write_json({ + command = table.concat(argv, " "), + stdout = not binary and stdout, + stderr = stderr, + exitcode = rv, + binary = binary + }) + else + luci.http.status(404, translate("No such command")) + end +end + +function action_download(...) + local fs = require "nixio.fs" + local argv = parse_cmdline(...) + if argv then + local fd = io.popen(table.concat(argv, " ") .. " 2>/dev/null") + if fd then + local chunk = fd:read(4096) or "" + local name + if chunk:match("[%z\1-\8\14-\31]") then + luci.http.header("Content-Disposition", "attachment; filename=%s" + % fs.basename(argv[1]):gsub("%W+", ".") .. ".bin") + luci.http.prepare_content("application/octet-stream") + else + luci.http.header("Content-Disposition", "attachment; filename=%s" + % fs.basename(argv[1]):gsub("%W+", ".") .. ".txt") + luci.http.prepare_content("text/plain") + end + + while chunk do + luci.http.write(chunk) + chunk = fd:read(4096) + end + + fd:close() + else + luci.http.status(500, translate("Failed to execute command")) + end + else + luci.http.status(404, "No such command") + end +end + +function action_public(cmdid, args) + local uci = require "luci.model.uci".cursor() + if cmdid and + uci:get("luci", cmdid) == "command" and + uci:get("luci", cmdid, "public") == "1" + then + action_download(cmdid, args) + else + luci.http.status(403, translate("Access to command denied")) + end +end + +function action_load_script() + local set = luci.http.formvalue("set") + local rv ={} + local file + + file = io.open(set, "r") + if file ~= nil then + local tmp = file:read("*all") + rv["text"] = tmp + file:close() + else + rv["text"] = translate("No file found") + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_save_script() + local line = luci.http.formvalue("set") + local rv ={} + local file + + s, e = line:find("|") + name = line:sub(1,s-1) + text = line:sub(e+1) + + file = io.open(name, "w") + file:write(text) + file:close() + os.execute("chmod 777 " .. name) + + rv["name"] = name + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_del_script() + local name = luci.http.formvalue("set") + local rv ={} + os.remove(name) + + rv["name"] = name + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end \ No newline at end of file diff --git a/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/model/cbi/commands.lua b/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/model/cbi/commands.lua new file mode 100644 index 0000000..1359eb2 --- /dev/null +++ b/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/model/cbi/commands.lua @@ -0,0 +1,37 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2012 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +]]-- + +local m, s + +m = Map("luci", translate("Custom Commands"), + translate("This page allows you to configure custom shell commands which can be easily invoked from the web interface.")) + +s = m:section(TypedSection, "command", "") +s.template = "cbi/tblsection" +s.anonymous = true +s.addremove = true + + +s:option(Value, "name", translate("Description"), + translate("A short textual description of the configured command")) + +s:option(Value, "command", translate("Command"), + translate("Command line to execute")) + +s:option(Flag, "param", translate("Custom arguments"), + translate("Allow the user to provide additional command line arguments")) + +s:option(Flag, "public", translate("Public access"), + translate("Allow executing the command and downloading its output without prior authentication")) + +return m diff --git a/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/view/cmdedit.htm b/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/view/cmdedit.htm new file mode 100644 index 0000000..cfd8a53 --- /dev/null +++ b/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/view/cmdedit.htm @@ -0,0 +1,186 @@ +<%+header%> + + + + +
+
+

<%:Script Editing%>

+
<%:Create, Edit and Save Scripts%>
+
+ + + + + + +
<%:Script Name :%>
 
+ + + + + + +
<%:Path to Script :%>
 
+ + + + + +
+ +
+ + + + + + + + + +
 
+ +
+ +
+
+<%+footer%> \ No newline at end of file diff --git a/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/view/commands.htm b/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/view/commands.htm new file mode 100644 index 0000000..83792a9 --- /dev/null +++ b/rooter/0basicapps/ext-command/files/usr/lib/lua/luci/view/commands.htm @@ -0,0 +1,176 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2012 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +-%> + +<% css = [[ + +.commandbox { + height: 12em; + width: 30%; + float: left; + height: 12em; + margin: 5px; + position: relative; +} + +.commandbox h3 { + font-size: 1.5em !important; + line-height: 2em !important; + margin: 0 !important; +} + +.commandbox input[type="text"] { + width: 50% !important; +} + +.commandbox div { + position: absolute; + left: 0; + bottom: 1.5em; +} + +]] -%> + +<%+header%> + + + + +<% + local uci = require "luci.model.uci".cursor() + local commands = { } + + uci:foreach("luci", "command", function(s) commands[#commands+1] = s end) +%> + +
"> +
+

<%:Custom Commands%>

+ +
+ <% local _, command; for _, command in ipairs(commands) do %> +
+

<%=pcdata(command.name)%>

+

<%:Command:%> <%=pcdata(command.command)%>

+ <% if command.param == "1" then %> +

<%:Arguments:%>

+ <% end %> +
+ + + <% if command.public == "1" then %> + + <% end %> +
+
+ <% end %> + +

+ +
+
+ + +
+ +<%+footer%> diff --git a/rooter/0basicapps/ext-command/files/usr/lib/scripts/dummy b/rooter/0basicapps/ext-command/files/usr/lib/scripts/dummy new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/rooter/0basicapps/ext-command/files/usr/lib/scripts/dummy @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/rooter/0basicapps/ext-extra/Makefile b/rooter/0basicapps/ext-extra/Makefile new file mode 100644 index 0000000..07a6c59 --- /dev/null +++ b/rooter/0basicapps/ext-extra/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-extra +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-extra + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Basic Applications + TITLE:=Add Scheduled Reboot + PKGARCH:=all +endef + +define Package/ext-extra/description + Helper scripts to install Scheduled Reboot +endef + + +define Build/Compile +endef + +define Package/ext-extra/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-extra)) diff --git a/rooter/0basicapps/ext-extra/files/etc/config/schedule b/rooter/0basicapps/ext-extra/files/etc/config/schedule new file mode 100644 index 0000000..95c1155 --- /dev/null +++ b/rooter/0basicapps/ext-extra/files/etc/config/schedule @@ -0,0 +1,7 @@ + +config reboot 'reboot' + option enable '0' + +config timezone 'timezone' + option zonename 'UTC' + diff --git a/rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/controller/schedule.lua b/rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/controller/schedule.lua new file mode 100644 index 0000000..d64b6c6 --- /dev/null +++ b/rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/controller/schedule.lua @@ -0,0 +1,13 @@ +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.schedule", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + + page = entry({"admin", "services", "schedule"}, cbi("schedule"), _(translate("Scheduled Reboot")), 61) + page.dependent = true +end diff --git a/rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/model/cbi/admin_system/cronnew.lua b/rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/model/cbi/admin_system/cronnew.lua new file mode 100644 index 0000000..0de690c --- /dev/null +++ b/rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/model/cbi/admin_system/cronnew.lua @@ -0,0 +1,29 @@ +-- Copyright 2008 Steven Barth +-- Copyright 2008-2013 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +local fs = require "nixio.fs" +local cronfile = "/etc/cronuser" + +f = SimpleForm("crontab", translate("Scheduled Tasks"), translate("This is the system crontab in which scheduled tasks can be defined.")) + +t = f:field(TextValue, "crons") +t.rmempty = true +t.rows = 10 +function t.cfgvalue() + return fs.readfile(cronfile) or "" +end + +function f.handle(self, state, data) + if state == FORM_VALID then + if data.crons then + fs.writefile(cronfile, data.crons:gsub("\r\n", "\n")) + else + fs.writefile(cronfile, "") + end + luci.sys.call("/usr/lib/rooter/luci/croncat.sh") + end + return true +end + +return f diff --git a/rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/model/cbi/schedule.lua b/rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/model/cbi/schedule.lua new file mode 100644 index 0000000..e6ddaa7 --- /dev/null +++ b/rooter/0basicapps/ext-extra/files/usr/lib/lua/luci/model/cbi/schedule.lua @@ -0,0 +1,133 @@ +local utl = require "luci.util" + +local sys = require "luci.sys" +local zones = require "luci.sys.zoneinfo" +local fs = require "nixio.fs" +local conf = require "luci.config" + +os.execute("/usr/lib/rooter/luci/reboot.sh 0") + +m = Map("schedule", translate("Scheduled Reboot"), translate("Schedule a Router Reboot at a Specified Time")) + +m.on_after_save = function(self) + luci.sys.call("/usr/lib/rooter/luci/reboot.sh 1 &") +end + +d1 = m:section(TypedSection, "timezone", " ") + +--o1 = d1:option(DummyValue, "_systime", translate("Local Time : ")) +--o1.template = "admin_system/clock_status" + +o = d1:option(DummyValue, "zonename", translate("Timezone : "), translate("Be sure to set your Timezone correctly in System->System")) + +d = m:section(TypedSection, "reboot", " ") + +c1 = d:option(ListValue, "enable", " "); +c1:value("0", translate("Disabled")) +c1:value("1", translate("Enabled")) +c1.default=0 + +sdhour = d:option(ListValue, "sdhour", translate("Reboot Time :")) +sdhour.rmempty = true +sdhour:value("0", "12:00 AM") +sdhour:value("1", "12:15 AM") +sdhour:value("2", "12:30 AM") +sdhour:value("3", "12:45 AM") +sdhour:value("4", "01:00 AM") +sdhour:value("5", "01:15 AM") +sdhour:value("6", "01:30 AM") +sdhour:value("7", "01:45 AM") +sdhour:value("8", "02:00 AM") +sdhour:value("9", "02:15 AM") +sdhour:value("10", "02:30 AM") +sdhour:value("11", "02:45 AM") +sdhour:value("12", "03:00 AM") +sdhour:value("13", "03:15 AM") +sdhour:value("14", "03:30 AM") +sdhour:value("15", "03:45 AM") +sdhour:value("16", "04:00 AM") +sdhour:value("17", "04:15 AM") +sdhour:value("18", "04:30 AM") +sdhour:value("19", "04:45 AM") +sdhour:value("20", "05:00 AM") +sdhour:value("21", "05:15 AM") +sdhour:value("22", "05:30 AM") +sdhour:value("23", "05:45 AM") +sdhour:value("24", "06:00 AM") +sdhour:value("25", "06:15 AM") +sdhour:value("26", "06:30 AM") +sdhour:value("27", "06:45 AM") +sdhour:value("28", "07:00 AM") +sdhour:value("29", "07:15 AM") +sdhour:value("30", "07:30 AM") +sdhour:value("31", "07:45 AM") +sdhour:value("32", "08:00 AM") +sdhour:value("33", "08:15 AM") +sdhour:value("34", "08:30 AM") +sdhour:value("35", "08:45 AM") +sdhour:value("36", "09:00 AM") +sdhour:value("37", "09:15 AM") +sdhour:value("38", "09:30 AM") +sdhour:value("39", "09:45 AM") +sdhour:value("40", "10:00 AM") +sdhour:value("41", "10:15 AM") +sdhour:value("42", "10:30 AM") +sdhour:value("43", "10:45 AM") +sdhour:value("44", "11:00 AM") +sdhour:value("45", "11:15 AM") +sdhour:value("46", "11:30 AM") +sdhour:value("47", "11:45 AM") +sdhour:value("48", "12:00 PM") +sdhour:value("49", "12:15 PM") +sdhour:value("50", "12:30 PM") +sdhour:value("51", "12:45 PM") +sdhour:value("52", "01:00 PM") +sdhour:value("53", "01:15 PM") +sdhour:value("54", "01:30 PM") +sdhour:value("55", "01:45 PM") +sdhour:value("56", "02:00 PM") +sdhour:value("57", "02:15 PM") +sdhour:value("58", "02:30 PM") +sdhour:value("59", "02:45 PM") +sdhour:value("60", "03:00 PM") +sdhour:value("61", "03:15 PM") +sdhour:value("62", "03:30 PM") +sdhour:value("63", "03:45 PM") +sdhour:value("64", "04:00 PM") +sdhour:value("65", "04:15 PM") +sdhour:value("66", "04:30 PM") +sdhour:value("67", "04:45 PM") +sdhour:value("68", "05:00 PM") +sdhour:value("69", "05:15 PM") +sdhour:value("70", "05:30 PM") +sdhour:value("71", "05:45 PM") +sdhour:value("72", "06:00 PM") +sdhour:value("73", "06:15 PM") +sdhour:value("74", "06:30 PM") +sdhour:value("75", "06:45 PM") +sdhour:value("76", "07:00 PM") +sdhour:value("77", "07:15 PM") +sdhour:value("78", "07:30 PM") +sdhour:value("79", "07:45 PM") +sdhour:value("80", "08:00 PM") +sdhour:value("81", "08:15 PM") +sdhour:value("82", "08:30 PM") +sdhour:value("83", "08:45 PM") +sdhour:value("84", "09:00 PM") +sdhour:value("85", "09:15 PM") +sdhour:value("86", "09:30 PM") +sdhour:value("87", "09:45 PM") +sdhour:value("88", "10:00 PM") +sdhour:value("89", "10:15 PM") +sdhour:value("90", "10:30 PM") +sdhour:value("91", "10:45 PM") +sdhour:value("92", "11:00 PM") +sdhour:value("93", "11:15 PM") +sdhour:value("94", "11:30 PM") +sdhour:value("95", "11:45 PM") + +sdhour:depends("enable", "1") +sdhour.default = "0" + +return m + diff --git a/rooter/0basicapps/ext-extra/files/usr/lib/rooter/luci/croncat.sh b/rooter/0basicapps/ext-extra/files/usr/lib/rooter/luci/croncat.sh new file mode 100644 index 0000000..842f648 --- /dev/null +++ b/rooter/0basicapps/ext-extra/files/usr/lib/rooter/luci/croncat.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +log() { + logger -t "Croncat" "$@" +} + +> /tmp/crontmp +if [ -e /etc/crontabs/root ]; then + while read -r line; do + if [ -n "$line" ]; then + if [ ${line: -1} == ";" ]; then + echo "$line" >> /tmp/crontmp + fi + fi + done < /etc/crontabs/root +fi + +if [ -f /etc/cronuser ]; then + if [ -f /etc/cronbase ]; then + cat /etc/cronbase /etc/cronuser > /etc/crontabs/root + else + cp /etc/cronuser /etc/crontabs/root + fi +else + if [ -f /etc/cronbase ]; then + cp /etc/cronbase /etc/crontabs/root + else + > /etc/crontabs/root + fi +fi +cat /tmp/crontmp /etc/crontabs/root > /tmp/cronroot +cp /tmp/cronroot /etc/crontabs/root +rm /tmp/crontmp +rm /tmp/cronroot + +/etc/init.d/cron restart diff --git a/rooter/0basicapps/ext-extra/files/usr/lib/rooter/luci/reboot.sh b/rooter/0basicapps/ext-extra/files/usr/lib/rooter/luci/reboot.sh new file mode 100644 index 0000000..eac8962 --- /dev/null +++ b/rooter/0basicapps/ext-extra/files/usr/lib/rooter/luci/reboot.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +log() { + logger -t "Schedule Reboot" "$@" +} + +PARM=$1 + +if [ $PARM = "0" ]; then + HO=$(uci get system.@system[-1].zonename) + if [ -z $HO ]; then + HO="UTC" + fi + uci set schedule.timezone.zonename="$HO" + uci commit schedule +fi + +if [ $PARM = "1" ]; then + sleep 5 + EN=$(uci get schedule.reboot.enable) + if [ $EN = "1" ]; then + SDHOUR=$(uci get schedule.reboot.sdhour) + HOUR=`expr $SDHOUR / 4` + let "TH = $HOUR * 4" + let "TMP1 = $SDHOUR - $TH" + let "MIN = $TMP1 * 15" + echo "$MIN $HOUR * * * sleep 70 && touch /etc/banner && reboot -f" > /etc/cronbase + else + rm -f /etc/cronbase + fi + /usr/lib/rooter/luci/croncat.sh +fi diff --git a/rooter/0basicapps/ext-p910nd/Makefile b/rooter/0basicapps/ext-p910nd/Makefile new file mode 100644 index 0000000..9f7dc57 --- /dev/null +++ b/rooter/0basicapps/ext-p910nd/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-p910nd +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-p910nd + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Basic Applications + DEPENDS:=+p910nd +kmod-usb-printer +kmod-usb-ohci + TITLE:=Install Print Server + PKGARCH:=all +endef + +define Package/ext-p910nd/description + Helper scripts to install print Server +endef + + +define Build/Compile +endef + +define Package/ext-p910nd/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-p910nd)) diff --git a/rooter/0basicapps/ext-p910nd/files/etc/uci-defaults/40_luci-p910ndx b/rooter/0basicapps/ext-p910nd/files/etc/uci-defaults/40_luci-p910ndx new file mode 100644 index 0000000..80f6d62 --- /dev/null +++ b/rooter/0basicapps/ext-p910nd/files/etc/uci-defaults/40_luci-p910ndx @@ -0,0 +1,11 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@p910nd[-1] + add ucitrack p910nd + set ucitrack.@p910nd[-1].init=p910nd + commit ucitrack +EOF + +rm -f /tmp/luci-indexcache +exit 0 diff --git a/rooter/0basicapps/ext-p910nd/files/usr/lib/lua/luci/controller/p910ndx.lua b/rooter/0basicapps/ext-p910nd/files/usr/lib/lua/luci/controller/p910ndx.lua new file mode 100644 index 0000000..c6feee8 --- /dev/null +++ b/rooter/0basicapps/ext-p910nd/files/usr/lib/lua/luci/controller/p910ndx.lua @@ -0,0 +1,18 @@ +-- Copyright 2008 Yanira +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.p910ndx", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + if not nixio.fs.access("/etc/config/p910nd") then + return + end + + local page + + page = entry({"admin", "services", "p910ndx"}, cbi("p910ndx"), _(translate("Print Server")), 60) + page.dependent = true +end diff --git a/rooter/0basicapps/ext-p910nd/files/usr/lib/lua/luci/model/cbi/p910ndx.lua b/rooter/0basicapps/ext-p910nd/files/usr/lib/lua/luci/model/cbi/p910ndx.lua new file mode 100644 index 0000000..12c4a58 --- /dev/null +++ b/rooter/0basicapps/ext-p910nd/files/usr/lib/lua/luci/model/cbi/p910ndx.lua @@ -0,0 +1,59 @@ +--[[ + +LuCI p910nd +(c) 2008 Yanira +(c) 2012 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +]]-- + +local uci = luci.model.uci.cursor_state() +local net = require "luci.model.network" +local m, s, p, b + +m = Map("p910nd", translate("Print Server"), + translatef("Support for USB Printers.")) + +net = net.init(m.uci) + +s = m:section(TypedSection, "p910nd", translate("Settings")) +s.addremove = true +s.anonymous = true + +s:option(Flag, "enabled", translate("enable")) + +s:option(Value, "device", translate("Device")).rmempty = true + +b = s:option(Value, "bind", translate("Interface"), translate("Specifies the interface to listen on.")) +b.template = "cbi/network_netlist" +b.nocreate = true +b.unspecified = true + +function b.cfgvalue(...) + local v = Value.cfgvalue(...) + if v then + return (net:get_status_by_address(v)) + end +end + +function b.write(self, section, value) + local n = net:get_network(value) + if n and n:ipaddr() then + Value.write(self, section, n:ipaddr()) + end +end + +p = s:option(ListValue, "port", translate("Port"), translate("TCP listener port.")) +p.rmempty = true +for i=0,9 do + p:value(i, 9100+i) +end + +s:option(Flag, "bidirectional", translate("Bidirectional mode")) + +return m diff --git a/rooter/0basicapps/usb-storage/Makefile b/rooter/0basicapps/usb-storage/Makefile new file mode 100644 index 0000000..e2b95c2 --- /dev/null +++ b/rooter/0basicapps/usb-storage/Makefile @@ -0,0 +1,38 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=usb-storage +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/usb-storage + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Basic Applications + DEPENDS:= +ntfs-3g +fdisk +kmod-usb-storage \ + +kmod-fs-ext4 +kmod-fs-vfat +kmod-nls-cp437 +kmod-nls-iso8859-1 +kmod-nls-utf8 \ + +block-mount +kmod-fs-exfat +kmod-fs-hfs +hd-idle + TITLE:=Install USB Storage + PKGARCH:=all +endef + +define Package/usb-storage/description + Helper scripts to install USB Storage +endef + + +define Build/Compile +endef + +define Package/usb-storage/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,usb-storage)) diff --git a/rooter/0basicapps/usb-storage/files/etc/config/umount b/rooter/0basicapps/usb-storage/files/etc/config/umount new file mode 100644 index 0000000..ca8f428 --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/etc/config/umount @@ -0,0 +1,2 @@ +config umount 'umount' + option drive '' diff --git a/rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/20-mount b/rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/20-mount new file mode 100644 index 0000000..961a219 --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/20-mount @@ -0,0 +1,68 @@ +#!/bin/sh /etc/rc.common +. /lib/functions.sh + +log() { + logger -t "20-mount" "$@" +} + +blkdev=`dirname $DEVPATH` +if [ `basename $blkdev` != "block" ]; then + device=`basename $DEVPATH` + if echo $device | grep -q "mtdblock"; then + exit 0 + fi + if [ -e /etc/sda_drop ]; then + source /etc/sda_drop + if echo $device | grep -q "$SDA"; then + exit 0 + fi + fi + if [ ! -e /usr/lib/sdcard/sdcard.sh ]; then + /usr/lib/sdcard/sdcard.sh detect + source /tmp/detect.file + if [ $detect = "1" ]; then + if echo $device | grep -q "mmcblk"; then + exit 0 + fi + fi + fi + if echo $device | grep -q "mmcblk"; then + device1="SDCard"${device:8:2} + else + device1=$device + fi + + case "$ACTION" in + add) + mkdir -p /mnt/$device1 + # vfat & ntfs-3g check + if [ `which fdisk` ]; then + isntfs=`fdisk -l | grep $device | grep NTFS` + isvfat=`fdisk -l | grep $device | grep FAT` + isfuse=`lsmod | grep fuse` + isntfs3g=`which ntfs-3g` + else + isntfs="" + isvfat="" + fi + # mount with ntfs-3g if possible, else with default mount + if [ "$isntfs" -a "$isfuse" -a "$isntfs3g" ]; then + ntfs-3g -o nls=utf8 /dev/$device /mnt/$device1 + log "Mount /mnt/$device as NTFS" + elif [ "$isvfat" ]; then + mount -o rw,sync,umask=002,codepage=437,iocharset=iso8859-1 /dev/$device /mnt/$device1 + log "Mount /mnt/$device as FAT" + else + mount -o rw,sync /dev/$device /mnt/$device1 + log "Mount /mnt/$device as other" + fi + + chmod 777 /mnt/$device1 + chown nobody /mnt/$device1 + + if [ -e /usr/lib/sdcard/sdcard.sh ]; then + /usr/lib/sdcard/sdcard.sh add + fi + ;; + esac +fi \ No newline at end of file diff --git a/rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/30-mount b/rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/30-mount new file mode 100644 index 0000000..7a1f933 --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/30-mount @@ -0,0 +1,88 @@ +#!/bin/sh /etc/rc.common +. /lib/functions.sh +# Copyright (C) 2011 OpenWrt.org + +log() { + logger -t "30-mount" "$@" +} + +sanitize() { + sed -e 's/[[:space:]]\+$//; s/[[:space:]]\+/_/g' "$@" +} + +blkdev=`dirname $DEVPATH` +if [ `basename $blkdev` != "block" ]; then + device=`basename $DEVPATH` + if echo $device | grep -q "mtdblock"; then + exit 0 + fi + if [ ! -e /usr/lib/sdcard/sdcard.sh ]; then + /usr/lib/sdcard/sdcard.sh detect + source /tmp/detect.file + if [ $detect = "1" ]; then + if echo $device | grep -q "mmcblk"; then + exit 0 + fi + fi + fi + if echo $device | grep -q "mmcblk"; then + device1="SDCard"${device:8:2} + else + device1=$device + fi + + if [ -e /etc/sda_drop ]; then + source /etc/sda_drop + if echo $device | grep -q "$SDA"; then + exit 0 + fi + fi + + case "$ACTION" in + add) + MT=$(cat /proc/mounts | grep "$device") + if [ -z $MT ]; then + exit 0 + fi + DEVN=${DEVNAME:0:3} + MODEL=$(sanitize "/sys/block/$DEVN/device/model") + if [ -d /etc/ksmbd ]; then + uci delete ksmbd.$device1 + uci set ksmbd.$device1=share + uci set ksmbd.$device1.name=$device1 + uci set ksmbd.$device1.path=/mnt/$device1 + uci set ksmbd.$device1.read_only=no + uci set ksmbd.$device1.guest_ok=yes + uci set ksmbd.$device1.create_mask='0666' + uci set ksmbd.$device1.dir_mask='0777' + uci commit ksmbd + /etc/init.d/ksmbd restart + log "/mnt/$device1 shared as $device1" + else + if [ -d /etc/samba ]; then + uci delete samba.$device1 + uci set samba.$device1=sambashare + uci set samba.$device1.name=$device1 + uci set samba.$device1.path=/mnt/$device1 + uci set samba.$device1.read_only=no + uci set samba.$device1.guest_ok=yes + uci commit samba + /etc/init.d/samba restart + log "/mnt/$device1 shared as $device1" + fi + fi + ;; + remove) + log "remove /mnt/$device1" + if [ -d /etc/ksmbd ]; then + uci delete ksmbd.$device1 + uci commit ksmbd + else + if [ -d /etc/samba ]; then + uci delete samba.$device1 + uci commit samba + fi + fi + ;; + esac +fi diff --git a/rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/99-mount b/rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/99-mount new file mode 100644 index 0000000..5594607 --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/etc/hotplug.d/block/99-mount @@ -0,0 +1,41 @@ +#!/bin/sh /etc/rc.common +. /lib/functions.sh + +log() { + logger -t "99-mount" "$@" +} + + +blkdev=`dirname $DEVPATH` +if [ `basename $blkdev` != "block" ]; then + device=`basename $DEVPATH` + if echo $device | grep -q "mtdblock"; then + exit 0 + fi + + if [ ! -e /usr/lib/sdcard/sdcard.sh ]; then + /usr/lib/sdcard/sdcard.sh detect + source /tmp/detect.file + if [ $detect = "1" ]; then + if echo $device | grep -q "mmcblk"; then + exit 0 + fi + fi + fi + if echo $device | grep -q "mmcblk"; then + device1="SDCard"${device:8:2} + else + device1=$device + fi + + case "$ACTION" in + remove) + log "remove /mnt/$device1" + umount -l /mnt/$device1 + rm -rf /mnt/$device1 + if [ -e /usr/lib/sdcard/sdcard.sh ]; then + /usr/lib/sdcard/sdcard.sh remove + fi + ;; + esac +fi \ No newline at end of file diff --git a/rooter/0basicapps/usb-storage/files/etc/uci-defaults/40_luci-hd_idle b/rooter/0basicapps/usb-storage/files/etc/uci-defaults/40_luci-hd_idle new file mode 100644 index 0000000..92f4356 --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/etc/uci-defaults/40_luci-hd_idle @@ -0,0 +1,11 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@hd-idle[-1] + add ucitrack hd-idle + set ucitrack.@hd-idle[-1].init=hd-idle + commit ucitrack +EOF + +rm -f /tmp/luci-indexcache +exit 0 diff --git a/rooter/0basicapps/usb-storage/files/etc/umount b/rooter/0basicapps/usb-storage/files/etc/umount new file mode 100644 index 0000000..8292a0f --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/etc/umount @@ -0,0 +1,18 @@ +#!/bin/sh + +log() { + logger -t "Umount" "$@" +} + +sleep 5 +DRV=$(uci get umount.umount.drive) +if [ -z $DRV ]; then + exit 0 +fi + +umount -l /mnt/$DRV + +rm -rf /mnt/$DRV + +uci set umount.umount.drive='' +uci commit umount diff --git a/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/controller/hd_idle.lua b/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/controller/hd_idle.lua new file mode 100644 index 0000000..0cd3229 --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/controller/hd_idle.lua @@ -0,0 +1,17 @@ +-- Copyright 2008 Yanira +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.hd_idle", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + if not nixio.fs.access("/etc/config/hd-idle") then + return + end + + local page + page = entry({"admin", "services", "hd_idle"}, cbi("hd_idle"), _(translate("Hard Drive Idle")), 60) + page.dependent = true +end diff --git a/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/controller/umount.lua b/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/controller/umount.lua new file mode 100644 index 0000000..37bcf31 --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/controller/umount.lua @@ -0,0 +1,11 @@ +module("luci.controller.umount", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + + page = entry({"admin", "services", "umount"}, cbi("umount", {hidesavebtn=true, hideresetbtn=true}), translate("Safely Eject Drive"), 25) + page.dependent = true +end diff --git a/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/model/cbi/hd_idle.lua b/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/model/cbi/hd_idle.lua new file mode 100644 index 0000000..1c3c18f --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/model/cbi/hd_idle.lua @@ -0,0 +1,28 @@ +-- Copyright 2008 Yanira +-- Licensed to the public under the Apache License 2.0. + +require("nixio.fs") + +m = Map("hd-idle", "Hard Drive Idle", + translate("This is a utility program for spinning-down external disks after a period of idle time.")) + +s = m:section(TypedSection, "hd-idle", translate("Settings")) +s.anonymous = true + +s:option(Flag, "enabled", translate("Enable")) + +disk = s:option(Value, "disk", translate("Disk")) +disk.rmempty = true +for dev in nixio.fs.glob("/dev/[sh]d[a-z]") do + disk:value(nixio.fs.basename(dev)) +end + +s:option(Value, "idle_time_interval", translate("Idle-time")).default = 10 +s.rmempty = true +unit = s:option(ListValue, "idle_time_unit", translate("Idle-time unit")) +unit.default = "minutes" +unit:value("minutes", translate("min")) +unit:value("hours", translate("h")) +unit.rmempty = true + +return m diff --git a/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/model/cbi/umount.lua b/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/model/cbi/umount.lua new file mode 100644 index 0000000..334fe7f --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/usr/lib/lua/luci/model/cbi/umount.lua @@ -0,0 +1,20 @@ +require("nixio.fs") + +m = Map("umount", "Safely Eject a Drive", + translate("Safely eject a drive from the router")) + +m.on_after_save = function(self) + luci.sys.call("/etc/umount &") +end + +drv = m:section(TypedSection, "umount", translate("Currently Mounted Drives")) +drv.anonymous = true + +disk = drv:option(Value, "drive", translate(" "), translate("Click Save and Apply to eject drive")) +disk.rmempty = true +for dev in nixio.fs.glob("/mnt/[sh]d[a-z][1-9]") do + dv = nixio.fs.basename(dev) + disk:value(nixio.fs.basename(dev)) +end + +return m \ No newline at end of file diff --git a/rooter/0basicapps/usb-storage/files/usr/lib/sdcard/sdcard.sh b/rooter/0basicapps/usb-storage/files/usr/lib/sdcard/sdcard.sh new file mode 100644 index 0000000..257d915 --- /dev/null +++ b/rooter/0basicapps/usb-storage/files/usr/lib/sdcard/sdcard.sh @@ -0,0 +1,88 @@ +#!/bin/sh + +log() { + logger -t "sdcard" "$@" +} + +h721() { + if [ $1 = "add" ]; then + echo "17" > /sys/class/gpio/export + echo "out" > /sys/class/gpio/gpio17/direction + echo 0 > /sys/class/gpio/gpio17/value + else + echo "17" > /sys/class/gpio/export + echo "out" > /sys/class/gpio/gpio17/direction + echo 1 > /sys/class/gpio/gpio17/value +fi +} + +wg1608() { + if [ $1 = "add" ]; then + echo timer > /sys/class/leds/zbt-wg3526:green:signal/trigger + echo 1000 > /sys/class/leds/zbt-wg3526:green:signal/delay_on + echo 0 > /sys/class/leds/zbt-wg3526:green:signal/delay_off + else + echo timer > /sys/class/leds/zbt-wg3526:green:signal/trigger + echo 0 > /sys/class/leds/zbt-wg3526:green:signal/delay_on + echo 1000 > /sys/class/leds/zbt-wg3526:green:signal/delay_off + fi +} + +ws7915() { + if [ $1 = "add" ]; then + echo timer > /sys/class/leds/sys/trigger + echo 1000 > /sys/class/leds/sys/delay_on + echo 0 > /sys/class/leds/sys/delay_off + else + echo timer > /sys/class/leds/sys/trigger + echo 0 > /sys/class/leds/sys/delay_on + echo 1000 > /sys/class/leds/sys/delay_off + fi +} + +ws1688() { + if [ $1 = "add" ]; then + echo timer > /sys/class/leds/usb/trigger + echo 1000 > /sys/class/leds/usb/delay_on + echo 0 > /sys/class/leds/usb/delay_off + else + echo timer > /sys/class/leds/usb/trigger + echo 0 > /sys/class/leds/usb/delay_on + echo 1000 > /sys/class/leds/usb/delay_off + fi +} + +ACTION=$1 +model=$(cat /tmp/sysinfo/model) + +case $ACTION in + "add"|"remove" ) + mod=$(echo $model | grep "H721") + if [ $mod ]; then + h721 $ACTION + fi + mod=$(echo $model | grep "WG1608") + if [ $mod ]; then + wg1608 $ACTION + fi + mod=$(echo $model | grep "WS7915") + if [ $mod ]; then + ws7915 $ACTION + fi + + mod=$(echo $model | grep "WS1688") + if [ $mod ]; then + ws1688 $ACTION + fi + ;; + "detect" ) + mod=$(echo $model | grep "Raspberry") + if [ $mod ]; then + echo 'detect="'"1"'"' > /tmp/detect.file + else + echo 'detect="'"0"'"' > /tmp/detect.file + fi + ;; +esac + + diff --git a/rooter/0basicsupport/ext-buttons/Makefile b/rooter/0basicsupport/ext-buttons/Makefile new file mode 100644 index 0000000..d4ae835 --- /dev/null +++ b/rooter/0basicsupport/ext-buttons/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-buttons +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-buttons + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Basic Support + TITLE:=Install button support + PKGARCH:=all +endef + +define Package/ext-buttons/description + Helper scripts to install button support +endef + + +define Build/Compile +endef + +define Package/ext-buttons/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-buttons)) diff --git a/rooter/0basicsupport/ext-buttons/files/etc/btnaction.sh b/rooter/0basicsupport/ext-buttons/files/etc/btnaction.sh new file mode 100644 index 0000000..82a4e4e --- /dev/null +++ b/rooter/0basicsupport/ext-buttons/files/etc/btnaction.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +FUNC=$1 + +reset_short() { + passwd -d root + reboot -f +} + +reset_long() { + mtd -r erase rootfs_data +} + +wifi() { + STATEFILE="/tmp/wifionoff.state" + + if [ $# -eq 1 ]; then + case $1 in + "up"|"on") + STATE=off + ;; + "down"|"off") + STATE=on + ;; + esac + else + if [ ! -e ${STATEFILE} ]; then + STATE=on + else + . ${STATEFILE} + fi + fi + if [ -z ${STATE} ]; then + STATE=on + fi + + if [ ${STATE} == "on" ]; then + /sbin/wifi down + STATE=off + else + /sbin/wifi up + STATE=on + fi + + echo "STATE=${STATE}" > ${STATEFILE} +} + +if [ $FUNC = "reset_short" ]; then + reset_short +fi +if [ $FUNC = "reset_long" ]; then + reset_long +fi +if [ $FUNC = "wifi" ]; then + wifi $2 +fi diff --git a/rooter/0basicsupport/ext-buttons/files/etc/hotplug.d/button/00-button b/rooter/0basicsupport/ext-buttons/files/etc/hotplug.d/button/00-button new file mode 100644 index 0000000..0efab99 --- /dev/null +++ b/rooter/0basicsupport/ext-buttons/files/etc/hotplug.d/button/00-button @@ -0,0 +1,26 @@ +#!/bin/sh +. /lib/functions.sh + +do_button () { + local button + local action + local handler + local min + local max + + config_get button $1 button + config_get action $1 action + config_get handler $1 handler + config_get min $1 min + config_get max $1 max + + [ "$ACTION" = "$action" -a "$BUTTON" = "$button" -a -n "$handler" ] && { + [ -z "$min" -o -z "$max" ] && eval $handler + [ -n "$min" -a -n "$max" ] && { + [ $min -le $SEEN -a $max -ge $SEEN ] && eval $handler + } + } +} + +config_load system +config_foreach do_button button \ No newline at end of file diff --git a/rooter/0basicsupport/ext-buttons/files/etc/hotplug.d/button/10-buttonchk b/rooter/0basicsupport/ext-buttons/files/etc/hotplug.d/button/10-buttonchk new file mode 100644 index 0000000..ea4f499 --- /dev/null +++ b/rooter/0basicsupport/ext-buttons/files/etc/hotplug.d/button/10-buttonchk @@ -0,0 +1,10 @@ +#!/bin/sh + +log() { + logger -t "Button Checker " "$@" +} + +log "Button Name : $BUTTON Action : $ACTION" + +log "$ACTION $SEEN" + diff --git a/rooter/0basicsupport/ext-buttons/files/etc/init.d/buttons b/rooter/0basicsupport/ext-buttons/files/etc/init.d/buttons new file mode 100644 index 0000000..1901e61 --- /dev/null +++ b/rooter/0basicsupport/ext-buttons/files/etc/init.d/buttons @@ -0,0 +1,16 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +log() { + logger -t "Buttons" "$@" +} + +START=98 + +start() { + local BTN=$(uci -q get system.@button[-1].button) +} + +stop() { + log "Stopping Buttons" +} diff --git a/rooter/0basicsupport/ext-buttons/files/usr/lib/lua/luci/controller/buttons.lua b/rooter/0basicsupport/ext-buttons/files/usr/lib/lua/luci/controller/buttons.lua new file mode 100644 index 0000000..70fa838 --- /dev/null +++ b/rooter/0basicsupport/ext-buttons/files/usr/lib/lua/luci/controller/buttons.lua @@ -0,0 +1,14 @@ +module("luci.controller.buttons", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + page = entry({"admin", "system", "buttons"}, cbi("buttons/buttons"), _(translate("Buttons")), 65) + page.dependent = true + end +end diff --git a/rooter/0basicsupport/ext-buttons/files/usr/lib/lua/luci/model/cbi/buttons/buttons.lua b/rooter/0basicsupport/ext-buttons/files/usr/lib/lua/luci/model/cbi/buttons/buttons.lua new file mode 100644 index 0000000..4f37569 --- /dev/null +++ b/rooter/0basicsupport/ext-buttons/files/usr/lib/lua/luci/model/cbi/buttons/buttons.lua @@ -0,0 +1,44 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +m = Map("system", translate("Buttons"), + translate("This page allows the configuration of custom button actions")) + +s = m:section(TypedSection, "button", "") +s.anonymous = true +s.addremove = true + +s:option(Value, "button", translate("Name")) + +act = s:option(ListValue, "action", + translate("Action"), + translate("Specifies the button state to handle")) + +act:value("released") +act:value("pressed") +act.default = "released" + +s:option(Value, "handler", + translate("Handler"), + translate("Path to executable which handles the button event")) + +min = s:option(Value, "min", translate("Minimum hold time")) +min.rmempty = true +min:depends("action", "released") + +max = s:option(Value, "max", translate("Maximum hold time")) +max.rmempty = true +max:depends("action", "released") + +return m \ No newline at end of file diff --git a/rooter/0basicsupport/ext-sms/Makefile b/rooter/0basicsupport/ext-sms/Makefile new file mode 100644 index 0000000..3315be2 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-sms +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-sms + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Basic Support + TITLE:=Install SMS support + PKGARCH:=all +endef + +define Package/ext-sms/description + Helper scripts to install SMS on ROOter +endef + + +define Build/Compile +endef + +define Package/ext-sms/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-sms)) diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/lua/luci/controller/sms.lua b/rooter/0basicsupport/ext-sms/files/usr/lib/lua/luci/controller/sms.lua new file mode 100644 index 0000000..aa9dc01 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/lua/luci/controller/sms.lua @@ -0,0 +1,160 @@ +module("luci.controller.sms", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local fs = require "nixio.fs" + + + + if not fs.stat("/etc/nosms") then + local page + page = entry({"admin", "modem", "sms"}, template("rooter/sms"), translate("短信功能"), 35) + page.dependent = true + + end + + entry({"admin", "modem", "check_read"}, call("action_check_read")) + entry({"admin", "modem", "del_sms"}, call("action_del_sms")) + entry({"admin", "modem", "send_sms"}, call("action_send_sms")) + entry({"admin", "modem", "change_sms"}, call("action_change_sms")) + entry({"admin", "modem", "change_smsdn"}, call("action_change_smsdn")) + entry({"admin", "modem", "change_smsflag"}, call("action_change_smsflag")) +end + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +function action_send_sms() + if package.path:find(";/usr/lib/sms/?.lua") == nil then + package.path = package.path .. ";/usr/lib/sms/?.lua" + end + smsnum = luci.model.uci.cursor():get("modem", "general", "smsnum") + local set = luci.http.formvalue("set") + local number = trim(string.sub(set, 1, 20)) + local txt = string.sub(set, 21) + local utf8togsm = require "utf8togsm" + utf8togsm.chktxt(txt) + local msg = utf8togsm["msg"] + local dcs = utf8togsm["dcs"] + txt = utf8togsm["txt"] + local rv = {} + local file = nil + local k = 1 + local status + local rfname = "/tmp/smssendstatus0000" + if msg == nil then + os.execute("if [ -e " .. rfname .. " ]; then rm " ..rfname .. "; fi") + os.execute("lua /usr/lib/sms/sendsms.lua " .. smsnum .. " " .. number .. " " .. dcs .. " " .. txt .. " 0000") + os.execute("sleep 3") + repeat + file = io.open(rfname, "r") + if file == nil then + os.execute("sleep 1") + end + k = k + 1 + until k > 25 or file ~=nil + if file == nil then + status = translate('Sending attempt timed out (fail)') + else + status = file:read("*line") + file:close() + os.remove (rfname) + end + else + status = msg + end + rv["status"] = status + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_del_sms() + local set = tonumber(luci.http.formvalue("set")) + if set ~= nil and set > 0 then + set = set - 1; + smsnum = luci.model.uci.cursor():get("modem", "general", "smsnum") + os.execute("/usr/lib/sms/delsms.sh " .. smsnum .. " " .. set) + os.execute("touch /tmp/smswakeup" .. smsnum) + end +end + +function action_check_read() + local rv ={} + local file + local line + smsnum = luci.model.uci.cursor():get("modem", "general", "smsnum") + conn = "Modem #" .. smsnum + rv["conntype"] = conn + support = luci.model.uci.cursor():get("modem", "modem" .. smsnum, "sms") + rv["ready"] = "0" + rv["menable"] = "0" + rv["mslots"] = "0" + if support == "1" then + rv["ready"] = "1" + result = "/tmp/smsresult" .. smsnum .. ".at" + file = io.open(result, "r") + if file ~= nil then + file:close() + file = io.open("/tmp/smstext" .. smsnum, "r") + if file == nil then + rv["ready"] = "3" + else + rv["menable"] = luci.model.uci.cursor():get("modem", "sms", "menable") + rv["mslots"] = luci.model.uci.cursor():get("modem", "sms", "slots") + rv["ready"] = "2" + local tmp = file:read("*line") + rv["used"] = tmp + tmp = file:read("*line") + rv["max"] = tmp + full = nil + + repeat + for j = 1, 4 do + line = file:read("*line") + if line ~= nil then + if j == 3 then + full = full .. string.char(29) + local i = tonumber(line) + for k = 1, i do + line = file:read("*line") + full = full .. line + if k < i then + full = full .. '
' + end + end + else + if full == nil then + full = line + else + full = full .. string.char(29) .. line + end + end + end + end + until line == nil + file:close() + rv["line"] = full + end + end + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_change_sms() + os.execute("/usr/lib/rooter/luci/modemchge.sh sms 1") +end + +function action_change_smsdn() + os.execute("/usr/lib/rooter/luci/modemchge.sh sms 0") +end + +function action_change_smsflag() + local set = tonumber(luci.http.formvalue("set")) + os.execute("/usr/lib/sms/toggle.sh " .. set) +end + diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/lua/luci/view/rooter/sms.htm b/rooter/0basicsupport/ext-sms/files/usr/lib/lua/luci/view/rooter/sms.htm new file mode 100644 index 0000000..fda6d81 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/lua/luci/view/rooter/sms.htm @@ -0,0 +1,525 @@ +<%+header%> + + + + +
+
+

<%:短信收å‘页é¢%>

+
<%:通过模å—å‘é€å’ŒæŽ¥æ”¶æ–‡æœ¬æ¶ˆæ¯%>
+
+ <%:通信模å—ä¿¡æ¯%> + + + + + + + +
    + + + +
    + <%:收到的短信%> + + + + + + + + + + + + +
    <%:SIMå¯å­˜æ”¾çš„短信空间 (æ¡)%>
    <%:已使用的SIM短信空间 (æ¡)%>
     
         
        + + + + + + + + + + + + + + + + +
         
        <%:å¯ç”¨æ¨¡å—到SIMå¡çš„短信传输%>
        + +
        <%:模å—ä¸Šçš„æœªè¯»ä¿¡æ¯æ•°é‡%>
         
           
           
          + + + + + + + + + + + + +
          <%:已读状æ€%>
          <%:å‘件人%>
          <%:Date%>
          <%:æ—¶é—´%>
          <%:短信%>
          + + + + + +
          + +
          + + + + + + + +
          <%:短信内容 :%>
             
            + + + + + + + + +
             
            + + <%:短信会è¯%> + + + + + + + +
            <%:收件人 :%>
             
            + + + + + + +
            + +
            + + + + + + + +
              
            + + + + + + + +
            <%:短信å‘é€çŠ¶æ€ :%>
               
              + +
              + +
              +
              +<%+footer%> + diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/delsms.sh b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/delsms.sh new file mode 100644 index 0000000..5294092 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/delsms.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Delete SMS" "$@" +} + +CURRMODEM=$1 +shift 1 +SLOTS="$@" + +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) + +SMSLOC=$(uci -q get modem.modem$CURRMODEM.smsloc) + +LOCKDIR="/tmp/smslock$CURRMODEM" +PIDFILE="${LOCKDIR}/PID" + +while [ 1 -lt 6 ]; do + if mkdir "${LOCKDIR}" &>/dev/null; then + echo "$$" > "${PIDFILE}" + for SLOT in $SLOTS + do + ATCMDD="AT+CPMS=\"$SMSLOC\";+CMGD=$SLOT" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + done + uci set modem.modem$CURRMODEM.smsnum=999 + uci commit modem + break + else + OTHERPID="$(cat "${PIDFILE}")" + if [ $? = 0 ]; then + if ! kill -0 $OTHERPID &>/dev/null; then + rm -rf "${LOCKDIR}" + fi + fi + sleep 1 + fi +done +rm -rf "${LOCKDIR}" diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/pack7bit.lua b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/pack7bit.lua new file mode 100644 index 0000000..bbd5661 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/pack7bit.lua @@ -0,0 +1,79 @@ +local pack7bit = {} + +function hasbit(x, p) + return x % (p + p) >= p +end + +function bitand(x, y) + local p = 1; local z = 0; local limit = x > y and x or y + while p <= limit do + if hasbit(x, p) and hasbit(y, p) then + z = z + p + end + p = p + p + end + return z +end + +function bitor(x, y) + local p = 1; local z = 0; local limit = x > y and x or y + while p <= limit do + if hasbit(x, p) or hasbit(y, p) then + z = z + p + end + p = p + p + end + return z +end + +function bitright(x, y) + return math.floor(x / 2 ^ y) +end + +function bitleft(x, y) + return x * 2 ^ y +end + +function pack7bit.pack(udl, txt) + maxb = math.ceil((tonumber(udl, 16) / 8) * 7) + udtab = {} + ii = 1 + jj = 1 + kk = 0 + repeat + ch = tonumber(txt:sub(jj, jj + 1), 16) + if ii == 1 then + udtab[kk + 1] = ch + elseif ii == 2 then + udtab[kk] = bitor(bitleft(bitand(ch, 1), 7), udtab[kk]) + udtab[kk + 1] = bitright(bitand(ch, 126), 1) + elseif ii == 3 then + udtab[kk] = bitor(bitleft(bitand(ch, 3), 6), udtab[kk]) + udtab[kk + 1] = bitright(bitand(ch, 124), 2) + elseif ii == 4 then + udtab[kk] = bitor(bitleft(bitand(ch, 7), 5), udtab[kk]) + udtab[kk + 1] = bitright(bitand(ch, 120), 3) + elseif ii == 5 then + udtab[kk] = bitor(bitleft((bitand(ch, 15)), 4), udtab[kk]) + udtab[kk + 1] = bitright(bitand(ch, 112), 4) + elseif ii == 6 then + udtab[kk] = bitor(bitleft(bitand(ch, 31), 3), udtab[kk]) + udtab[kk + 1] = bitright(bitand(ch, 96), 5) + elseif ii == 7 then + udtab[kk] = bitor(bitleft(bitand(ch, 63), 2), udtab[kk]) + udtab[kk + 1] = bitright(bitand(ch, 64), 6) + else + udtab[kk] = bitor(bitleft(ch, 1), udtab[kk]) + ii = 0 + kk = kk - 1 + end + ii = ii + 1 + jj = jj + 2 + kk = kk + 1 + until jj > #txt + for jj = 1, maxb do + udtab[jj] = string.format("%02X", udtab[jj]) + end + pack7bit["pdu"] = table.concat(udtab) +end +return pack7bit diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/processsms b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/processsms new file mode 100644 index 0000000..8826bb2 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/processsms @@ -0,0 +1,168 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "sms process" "$@" +} + +CURRMODEM=$1 + +log "SMS Supported Modem$CURRMODEM" + +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) + +LOCKDIR="/tmp/smslock$CURRMODEM" +PIDFILE="${LOCKDIR}/PID" +rm -rf "${LOCKDIR}" + +idV=$(uci -q get modem.modem$CURRMODEM.idV) +idP=$(uci -q get modem.modem$CURRMODEM.idP) +MODEMID="$idV${idP:0:3}" + +ATCMDD="AT+CMGF=0" +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +sleep 1 +ATCMDD="AT+CPMS=\"SM\",\"SM\",\"SM\"" +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +MAXED=$(echo "$OX" | cut -d, -f2 | grep -o "[0-9]\{1,3\}") +if [ "$MAXED" == "0" -a "$MODEMID" != "119968a" ]; then + ATCMDD="AT+CPMS=\"ME\",\"ME\",\"ME\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + uci set modem.modem$CURRMODEM.smsloc="ME" + SMSLOC="ME" + MEM3="ME" +else + uci set modem.modem$CURRMODEM.smsloc="SM" + SMSLOC="SM" + MEM3="SM" +fi +sleep 1 +uci set modem.modem$CURRMODEM.smsnum=999 +uci commit modem +ATCMDD="AT+CPMS=\"ME\"" +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +MESC=$(echo "$OX" | grep -o "+CPMS:.*" | awk -F, '{print $1}' | grep -o "[0-9]\{1,3\}") +METC=$(echo "$OX" | grep -o "+CPMS:.*" | awk -F, '{print $2}' | grep -o "[0-9]\{1,3\}") +MESLOT="0" +MESCc="" +if [ "x$MESC" = "x" ]; then + MESC="0" +fi +if [ "x$METC" = "x" ]; then + METC="0" + MESC="0" + SMSLOC="SM" +fi +uci set modem.sms.slots=$MESC +uci commit modem +sleep 1 + +rm -f /tmp/smsresult$CURRMODEM".at" +> /tmp/smsslots$CURRMODEM +HH=$(date +%H) + +while true; do + SLEEP="20" + while true; do + if mkdir "${LOCKDIR}" &>/dev/null; then + echo "$$" > "${PIDFILE}" + if [ "$METC" != "0" ]; then + ATCMDD="AT+CPMS=\"ME\",\"$SMSLOC\",\"$MEM3\"" + SX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + USED=$(echo "$SX" | cut -d, -f1 | grep -o "[0-9]\{1,3\}") + MESCc="$USED" + MAXED=$(echo "$SX" | cut -d, -f2 | grep -o "[0-9]\{1,3\}") + fi + if [ $SMSLOC == "SM" ]; then + ATCMDD="AT+CPMS=\"SM\",\"$SMSLOC\",\"$MEM3\"" + SX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + USED=$(echo "$SX" | cut -d, -f1 | grep -o "[0-9]\{1,3\}") + MAXED=$(echo "$SX" | cut -d, -f2 | grep -o "[0-9]\{1,3\}") + if [ -n "$MESCc" -a "$MESCc" != "$MESC" ]; then + MESC=$MESCc + uci set modem.sms.slots=$MESC + uci commit modem + fi + if [ $USED == $MAXED -a $MEM3 == "SM" ]; then + ATCMDD="AT+CPMS=\"SM\",\"SM\",\"ME\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + MEM3="ME" + else + if [ $USED != $MAXED -a $MEM3 == "ME" ]; then + ATCMDD="AT+CPMS=\"SM\",\"SM\",\"SM\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + MEM3="SM" + fi + fi + fi + if [ $MAXED -eq 0 ]; then + SLEEP="900" + fi + if [ $USED -eq $(uci get modem.modem$CURRMODEM.smsnum) ] && [ $HH -eq $(date +%H) ]; then + if [ $MEM3 == "SM" -a $USED -lt $MAXED -a $MESC -gt 0 -a $(uci -q get modem.sms.menable) == 1 ]; then + ATCMDD="AT+CPMS=\"ME\";+CMGR=$MESLOT;+CPMS=\"SM\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + Rstat=$(echo "$OX" | grep -o "+CMGR:[^,]\+" | grep -o "[0-3]") + PDU=$(echo "$OX" | grep -o "[0-9A-F]\{30,\}") + PDUL=$(echo "$OX" | grep -o "+CMGR:.*" | grep -o ",[0-9]\{1,\}" | grep -o "[0-9]\{1,3\}") + if [ -n "$PDU" -a -n "$PDUL" -a -n "$Rstat" ]; then + if [ ${#PDUL} -eq 2 ]; then + PDUL="0$PDUL" + fi + ATCMDD="$PDUL,SM,$Rstat,$PDU" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "smswrite.gcom" "$CURRMODEM" "$ATCMDD") + MREF=$(echo "$OX" | grep -o "[0-9]\{1,3\}") + if [ ${#MREF} -gt 0 ]; then + echo "$MREF" >> /tmp/smsslots$CURRMODEM + ATCMDD="AT+CPMS=\"ME\";+CMGD=$MESLOT;+CPMS=\"SM\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + MESC=$(($MESC - 1)) + uci set modem.sms.slots=$MESC + uci commit modem + SLEEP="5" + fi + MESLOT=$(($MESLOT + 1)) + if [ $MESLOT -gt $METC -o $MESC == "0" ]; then + MESLOT="0" + fi + fi + else + log "Reread SMS Messages on Modem $CURRMODEM" + echo "$SX" > /tmp/smstemp$CURRMODEM + ATCMDD="AT+CMGL=4" + SX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + SX=$(echo "$SX" | sed -e "s/+CMGL:/+CMGL: /g") + echo "$SX" >> /tmp/smstemp$CURRMODEM + uci set modem.modem$CURRMODEM.smsnum=$USED + uci commit modem + mv /tmp/smstemp$CURRMODEM /tmp/smsresult$CURRMODEM.at + lua /usr/lib/sms/smsread.lua $CURRMODEM + HH=$(date +%H) + SLEEP="5" + fi + break + else + OTHERPID="$(cat "${PIDFILE}")" + if [ $? = 0 ]; then + if ! kill -0 $OTHERPID &>/dev/null; then + rm -rf "${LOCKDIR}" + fi + fi + sleep 1 + fi + done + rm -rf "${LOCKDIR}" + n=1 + until [ $n -ge $SLEEP ] + do + sleep 1 + if [ -e /tmp/smswakeup$CURRMODEM ]; then + rm /tmp/smswakeup$CURRMODEM + n=$(( $n + $SLEEP )) + else + n=$(( $n + 1 )) + fi + done +done diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sendsms.lua b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sendsms.lua new file mode 100644 index 0000000..baee895 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sendsms.lua @@ -0,0 +1,41 @@ +#!/usr/bin/lua + +modem = arg[1] +addr = arg[2] +dcs = arg[3] +txt = arg[4] +suffix = arg[5] + +if package.path:find(";/usr/lib/sms/?.lua") == nil then + package.path = package.path .. ";/usr/lib/sms/?.lua" +end + +local pack7bit = require "pack7bit" + +udl = string.format("%02X", math.floor(#txt / 2)) +da = "81" +if addr:sub(1, 1) == "+" then + da = "91" + addr = addr:sub(2) +elseif addr:sub(1, 1) == "-" then + addr = addr:sub(2) +end +da = string.format("%02X", #addr) .. da +if (#addr % 2) > 0 then + addr = addr .. "F" +end +k = #addr +j = 1 +repeat + da = da .. addr:sub(j + 1, j + 1) .. addr:sub(j, j) + j = j + 2 +until j > k +if dcs == "00" then + pack7bit.pack(udl, txt) + ud = pack7bit["pdu"] +else + ud = txt +end +pdu = "001100" .. da .. "00" .. dcs .. "AD" .. udl .. ud +pdul = string.format("%03d", (math.floor(#pdu / 2) - 1)) +os.execute("/usr/lib/sms/sendsms.sh " .. modem .. " " .. pdul .. "," .. suffix .. "," .. pdu .. " &") diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sendsms.sh b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sendsms.sh new file mode 100644 index 0000000..fad0e9c --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sendsms.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +CURRMODEM=$1 +ATCMDD=$2 + +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) + +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "sendsms-at.gcom" "$CURRMODEM" "$ATCMDD") diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsout.lua b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsout.lua new file mode 100644 index 0000000..3237ca5 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsout.lua @@ -0,0 +1,24 @@ +#!/usr/bin/lua + +local modem = arg[1] +local dest = arg[2] +local txt = arg[3] +local pid = arg[4] +local rfname = "/tmp/smssendstatus" .. pid + +if package.path:find(";/usr/lib/sms/?.lua") == nil then + package.path = package.path .. ";/usr/lib/sms/?.lua" +end + +local utf8togsm = require "utf8togsm" +utf8togsm.chktxt(txt) +local msg = utf8togsm["msg"] +local dcs = utf8togsm["dcs"] +txt = utf8togsm["txt"] + +if msg == nil then + os.execute("if [ -e " .. rfname .. " ]; then rm " ..rfname .. "; fi") + os.execute("lua /usr/lib/sms/sendsms.lua " .. modem .. " " .. dest .. " " .. dcs .. " " .. txt .. " " .. pid) +else + os.execute('echo "SMS sending failed - text is too long" > ' .. rfname) +end diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsout.sh b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsout.sh new file mode 100644 index 0000000..2c28887 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsout.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "sms process" "$@" +} + +CURRMODEM=$(uci get modem.general.smsnum) + +DEST="$1" +shift 1 +TXT="$@" +MYPID=$(printf "%05d" $$) +MYPID=$(printf "${MYPID:1:4}") +RESFILE="/tmp/smssendstatus"$MYPID + +lua /usr/lib/sms/smsout.lua $CURRMODEM $DEST "$TXT" $MYPID +sleep 5 +COUNT=0 +XSTATUS=1 +RES="SMS sending failed, timeout reading result" +while [ $COUNT -lt 15 ]; do + if [ -e $RESFILE ]; then + read RES < $RESFILE + if [ "${RES:0:9}" = "SMS sent," ]; then + XSTATUS=0 + fi + COUNT=999 + rm $RESFILE + else + sleep 2 + fi + COUNT=$(($COUNT + 1)) +done +log "$RES" +echo "$RES" +exit $XSTATUS diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsread.lua b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsread.lua new file mode 100644 index 0000000..c881724 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/smsread.lua @@ -0,0 +1,862 @@ +#!/usr/bin/lua + +senders2delete = {} +deletebinaries = false + +modemn = arg[1] + +local smsresult = "/tmp/smsresult" .. modemn .. ".at" +local smsslots = "/tmp/smsslots" .. modemn +local smstime = "/tmp/smstime" .. modemn +local t = {} +local tptr +local m_pdu_ptr +local m_pdu +local m_smsc +local m_with_udh +local m_report +local m_number +local m_replace +local m_alphabet +local m_dcs +local m_flash +local m_date +local m_time +local m_text +local m_concat +local m_read +local m_index +local g_table1 = {} +local g_table2 = {} + +local max_smsc = 64 +local max_number = 64 +local max_udh_data = 512 +surrogate = 0 + +function reset() + m_smsc = nil + m_with_udh = 0 + m_report = 0 + m_number = nil + m_replace = 0 + m_alphabet = -1 + m_flash = 0 + m_date = nil + m_time = nil + m_text = nil + m_concat = nil +end + +function hasbit(x, p) + return x % (p + p) >= p +end + +function bitor(x, y) + local p = 1; local z = 0; local limit = x > y and x or y + while p <= limit do + if hasbit(x, p) or hasbit(y, p) then + z = z + p + end + p = p + p + end + return z +end + +function bitand(x, y) + local p = 1; local z = 0; local limit = x > y and x or y + while p <= limit do + if hasbit(x, p) and hasbit(y, p) then + z = z + p + end + p = p + p + end + return z +end + +function bitright(x, y) + return math.floor(x / 2 ^ y) +end + +function bitleft(x, y) + return x * 2 ^ y +end + +function ocount(x, y) + local j = 0 + local i = x:find(y, 0) + while i ~= nil do + i = x:find(y, i + 1) + j = j + 1 + end + return j +end + +printf = function(s,...) + if echo == 0 then + io.write(s:format(...)) + else + ss = s:format(...) + os.execute("/usr/lib/rooter/logprint.sh " .. ss) + end +end + +function isxdigit(digit) + if digit == nil then + return 0 + end + if digit >= 48 and digit <= 57 then + return 1 + end + if digit >= 97 and digit <= 102 then + return 1 + end + if digit >= 65 and digit <= 70 then + return 1 + end + return 0 +end + +function isdigit(digit) + if digit >= 48 and digit <= 57 then + return 1 + end + return 0 +end + +function octet2bin(octet) + result = 0 + if octet:byte(1) > 57 then + result = result + octet:byte(1) - 55 + else + result = result + octet:byte(1) - 48 + end + result = result * 16 + if octet:byte(2) > 57 then + result = result + octet:byte(2) - 55 + else + result = result + octet:byte(2) - 48 + end + return result +end + +function octet2bin_check(octet) + if octet:byte(1) == 0 then + return -1 + end + if octet:byte(2) == 0 then + return -2 + end + if isxdigit(octet:byte(1)) == 0 then + return -3 + end + if isxdigit(octet:byte(2)) == 0 then + return -4 + end + return octet2bin(octet) +end + +function swapchars(sstring) + local length = sstring:len() + local xstring = nil + local i = 1 + while i < length do + c1 = sstring:sub(i, i) + c2 = sstring:sub(i+1, i+1) + if xstring == nil then + xstring = c2 .. c1 + else + xstring = xstring .. c2 .. c1 + end + i = i + 2 + end + return xstring +end + +function parseSMSC() + m_pdu_ptr = m_pdu + local length = octet2bin_check(m_pdu_ptr) + if length < 0 then + return -1 + end + if length == 0 then + m_smsc = "" + m_pdu_ptr = m_pdu_ptr:sub(3) + return 1 + end + if length < 2 or length > max_smsc then + return -1 + end + length = (length * 2) - 2 + local mlen = m_pdu:len() + if mlen < (length + 4) then + return -1 + end + m_pdu_ptr = m_pdu_ptr:sub(3) + local addr_type = octet2bin_check(m_pdu_ptr) + if addr_type < 0 then + return -1 + end + if addr_type < 0x80 then + return -1 + end + m_pdu_ptr = m_pdu_ptr:sub(3) + m_smsc = m_pdu_ptr:sub(0, length) + m_smsc = swapchars(m_smsc) + if addr_type < 0x90 then + for j=1, length do + if isxdigit(m_smsc:byte(j)) == 0 then + return -1 + end + end + else + if m_smsc:byte(length) == 70 then + m_smsc = m_smsc:sub(1, length-1) + end + local leng = m_smsc:len() + for j=1,leng do + if isdigit(m_smsc:byte(j)) == 0 then + return -1 + end + end + end + m_pdu_ptr = m_pdu_ptr:sub(length + 1) + return 1 +end + +function explainAddressType(octet_char, octet_int) + local result + if octet_char ~= nil then + result = octet2bin_check(octet_char) + else + result = octet_int + end + return result +end + +function concatinfo(x) + while #x > 9 do + if x:sub(1, 4) == '0003' then + if x:sub(7, 10) ~= '0101' then + m_concat = 'Msg# ' .. tonumber(x:sub(5, 6), 16) + m_concat = m_concat .. ',' .. tonumber(x:sub(9, 10), 16) + m_concat = m_concat .. '/' .. tonumber(x:sub(7, 8), 16) + end + x = "" + elseif x:sub(1, 4) == '0804' then + if x:sub(9, 12) ~= '0101' then + m_concat = 'Msg# ' .. tonumber(x:sub(5, 8), 16) + m_concat = m_concat .. ',' .. tonumber(x:sub(11, 12), 16) + m_concat = m_concat .. '/' .. tonumber(x:sub(9, 10), 16) + end + x = "" + else + local iel = tonumber(x:sub(3, 4), 16) + x = x:sub(5 + iel * 2) + end + end +end + +function pdu2binary(pdu, with_udh) + local skip_octets = 0 + local octetcounter + m_text = '' + local octets = octet2bin_check(pdu) + local last_i = 0 + if octets < 0 then + return -1 + end + if with_udh > 0 then + local pdu2 = pdu:sub(3) + local udhl = tonumber(pdu2:sub(1, 2), 16) + concatinfo(pdu2:sub(3, (udhl + 1) * 2)) + local udhsize = octet2bin_check(pdu2) + if udhsize < 0 then + return -1 + end + skip_octets = udhsize + 1 + end + for octetcounter = 0, (octets - skip_octets - 1) do + local pdu2 = pdu:sub((octetcounter * 2) + 3 + (skip_octets * 2)) + local i = octet2bin_check(pdu2) + if i < 0 then + return -1 + end + if m_alphabet == 2 then + if (2 + octetcounter) % 2 == 0 then + last_i = i + else + m_text = word2utf8(bitor(bitleft(last_i, 8), i), m_text) + end + else + if i < 32 or i > 127 then + i = 0x25A1 + end + m_text = word2utf8(i, m_text) + end + end + return (octets - skip_octets) +end + +function pdu2text(pdu, with_udh) + local result + local octetcounter + local skip_characters = 0 + local binary = 0 + m_text = '' + local septets = octet2bin_check(pdu) + if septets < 0 then + return -1 + end + if with_udh > 0 then + local pdu2 = pdu:sub(3) + local udhl = tonumber(pdu2:sub(1, 2), 16) + concatinfo(pdu2:sub(3, (udhl + 1) * 2)) + local udhsize = octet2bin_check(pdu2) + skip_characters = math.floor((((udhsize+1)*8)+6)/7) + end + local octets = math.floor((septets * 7 + 7) / 8) + local bitposition = 0 + local byteposition + local byteoffset + local i + local g_table_nbr = 1 + octetcounter = 0 + for charcounter=0,septets-1 do + local c = 0 + for bitcounter=0,6 do + byteposition = math.floor(bitposition / 8) + byteoffset = bitposition % 8 + while (byteposition >= octetcounter) and (octetcounter < octets) do + local pdu2 = pdu:sub((octetcounter * 2) + 3) + i = octet2bin_check(pdu2) + if i < 0 then + return -2 + end + binary = i + octetcounter = octetcounter + 1 + end + if bitand(binary, (2^byteoffset)) > 0 then + c = bitor(c, 128) + end + bitposition = bitposition + 1 + c = bitand(math.floor(c / 2), 127) + end + c = gsm2byte(c) + if charcounter >= skip_characters and c ~= 27 then + m_text = word2utf8(c, m_text) + end + end + return 1 +end + +function gsm2byte(ch) + if g_table_nbr == 2 then + if g_table2[ch] == nil then + ch = 63 + else + ch = g_table2[ch] + end + g_table_nbr = 1 + else + if ch == 27 then + g_table_nbr = 2 + else + if g_table1[ch] ~= nil then + ch = g_table1[ch] + end + end + end + return ch +end + +function word2utf8(i, txt) + if surrogate > 0 then + if i >= 0xDC00 and i <= 0xDFFF then + local ii = 0x10000 + bitand(i, 0x3FF) + bitleft(bitand(surrogate, 0x3FF), 10) + txt = txt .. string.char(bitor(0xF0, bitright(bitand(ii, 0x1C0000), 18))) + txt = txt .. string.char(bitor(0x80, bitright(bitand(ii, 0x3F000), 12))) + txt = txt .. string.char(bitor(0x80, bitright(bitand(ii, 0xFC0), 6))) + txt = txt .. string.char(bitor(0x80, bitand(ii, 0x3F))) + else + txt = txt .. string.char(0xe2) .. string.char(0x96) .. string.char(0xa1) + end + surrogate = 0 + elseif i >= 0xD800 and i <= 0xDBFF then + surrogate = i + elseif i >= 0xDC00 and i <= 0xDFFF then + txt = txt .. string.char(0xe2) .. string.char(0x96) .. string.char(0xa1) + elseif i < 0x80 then + txt = txt .. string.char(i) + elseif i < 0x800 then + txt = txt .. string.char(bitor(0xC0, bitright(bitand(i, 0x7C0), 6))) + txt = txt .. string.char(bitor(0x80, bitand(i, 0x3F))) + else + if i == 0x2029 then + txt = txt .. string.char(10) + else + txt = txt .. string.char(bitor(0xE0, bitright(bitand(i, 0xF000), 12))) + txt = txt .. string.char(bitor(0x80, bitright(bitand(i, 0xFC0), 6))) + txt = txt .. string.char(bitor(0x80, bitand(i, 0x3F))) + end + end + return txt +end + +function parseDeliver() + if m_pdu_ptr:len() < 4 then + return 0 + end + local padding = 0 + local length = octet2bin_check(m_pdu_ptr) + local timezone + if length < 0 or length > max_number then + return 0 + end +-- Sender Address + if length == 0 then + m_pdu_ptr = m_pdu_ptr:sub(5) + else + padding = length % 2 + m_pdu_ptr = m_pdu_ptr:sub(3) + local addr_type = explainAddressType(m_pdu_ptr, 0) + if addr_type < 0 then + return 0 + end + if addr_type < 0x80 then + return 0 + end + m_pdu_ptr = m_pdu_ptr:sub(3) + if bitand(addr_type, 112) == 80 then + if m_pdu_ptr:len() < (length + padding) then + return 0 + end + local htmp = string.format("%x", math.floor((length * 4) / 7)) + if htmp:len() < 2 then + htmp = "0" .. htmp + end + htmp = htmp:upper() + local tpdu = htmp .. m_pdu_ptr + local res = pdu2text(tpdu, 0) + if res < 0 then + return 0 + end + m_number = string.gsub(m_text, "\n", " ") + m_text = nil + else + m_number = m_pdu_ptr:sub(1, length + padding + 1) + m_number = swapchars(m_number) + if m_number:byte(length + padding) == 70 then + m_number = m_number:sub(1, length + padding - 1) + end + if addr_type == 145 then + m_number = "+" .. m_number + end + end + end + m_pdu_ptr = m_pdu_ptr:sub(length + padding + 1) + if m_pdu_ptr:len() < 20 then + return 0 + end +-- PID + local byte_buf = octet2bin_check(m_pdu_ptr) + if byte_buf < 0 then + return 0 + end + if bitand(byte_buf, 0xF8) == 0x40 then + m_replace = bitand(byte_buf, 0x07) + end + m_pdu_ptr = m_pdu_ptr:sub(3) +-- Alphabet + byte_buf = octet2bin_check(m_pdu_ptr) + if byte_buf < 0 then + return 0 + end + m_alphabet = math.floor(bitand(byte_buf, 0x0C) / 4) + if m_alphabet == 3 then + return 0 + end + if m_alphabet == 0 then + m_alphabet = -1 + end +-- DCS, Flash Msg + m_dcs = byte_buf + if bitand(byte_buf, 0x10) > 0 then + if bitand(byte_buf, 0x01) > 0 then + m_flash = 1 + end + end + m_pdu_ptr = m_pdu_ptr:sub(3) +-- Date + local str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. "-" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. "-" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5) + if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then + return 0 + end + m_date = str_buf + m_pdu_ptr = m_pdu_ptr:sub(7) +-- Time + str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. ":" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. ":" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5) + if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then + return 0 + end + if tonumber(m_pdu_ptr:sub(8,8), 16) > 7 then + timezone = '-' .. ((tonumber(m_pdu_ptr:sub(8, 8), 16) - 8) .. tonumber(m_pdu_ptr:sub(7, 7), 16)) / 4 + else + timezone = '+' .. (m_pdu_ptr:sub(8, 8) .. tonumber(m_pdu_ptr:sub(7, 7), 16)) / 4 + end + if timezone:sub(-2, -1) == '.0' then + timezone = timezone:sub(1, -3) + end + m_time = str_buf .. ' ' .. timezone .. 'h' + m_pdu_ptr = m_pdu_ptr:sub(7) + if octet2bin_check(m_pdu_ptr) < 0 then + return 0 + end + m_pdu_ptr = m_pdu_ptr:sub(3) + +-- Text + local result = 0 + local bin_udh = 1 + if m_alphabet <= 0 then + result = pdu2text(m_pdu_ptr, m_with_udh) + return result + else + result = pdu2binary(m_pdu_ptr, m_with_udh) + return result + end + return 1 +end + +function parseStatusReport() + if m_pdu_ptr:len() < 6 then + return 0 + end + local messageid = octet2bin_check(m_pdu_ptr) + if messageid < 0 then + return 0 + end + m_pdu_ptr = m_pdu_ptr:sub(3) + local length = octet2bin_check(m_pdu_ptr) + if length < 1 or length > max_number then + return 0 + end + local padding = length % 2 + m_pdu_ptr = m_pdu_ptr:sub(3) + local addr_type = explainAddressType(m_pdu_ptr, 0) + if addr_type < 0x80 then + return 0 + end + m_pdu_ptr = m_pdu_ptr:sub(3) + if bitand(addr_type, 112) == 80 then + if m_pdu_ptr:len() < (length + padding) then + return 0 + end + local htmp = string.format("%x", math.floor((length * 4) / 7)) + if htmp:len() < 2 then + htmp = "0" .. htmp + end + local tpdu = htmp .. m_pdu_ptr + local res = pdu2text(tpdu, 0) + if res < 0 then + return 0 + end + m_number = m_text + m_text = nil + else + m_number = m_pdu_ptr:sub(1, length + padding + 1) + m_number = swapchars(m_number) + if m_number:byte(length + padding) == 70 then + m_number = m_number:sub(1, length + padding - 1) + end + end + m_pdu_ptr = m_pdu_ptr:sub(length + padding + 1) + if m_pdu_ptr:len() < 14 then + return 0 + end +-- Date + local str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. "-" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. "-" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5) + if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then + return 0 + end + m_date = str_buf + m_pdu_ptr = m_pdu_ptr:sub(7) +-- Time + str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. ":" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. ":" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5) + if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then + return 0 + end + m_time = str_buf + m_pdu_ptr = m_pdu_ptr:sub(7) + if octet2bin_check(m_pdu_ptr) < 0 then + return 0 + end + m_pdu_ptr = m_pdu_ptr:sub(3) +-- Discharge Date + local str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. "-" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. "-" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5) + if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then + return 0 + end + local d_date = str_buf + m_pdu_ptr = m_pdu_ptr:sub(7) +-- Time + str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. ":" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. ":" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5) + if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then + return 0 + end + local d_time = str_buf + m_pdu_ptr = m_pdu_ptr:sub(7) + if octet2bin_check(m_pdu_ptr) < 0 then + return 0 + end + m_pdu_ptr = m_pdu_ptr:sub(3) + local status = octet2bin_check(m_pdu_ptr) + if status < 0 then + return 0 + end + m_text = string.format("Discharge Timestamp: %s %s Message ID: %d Status: %d", d_date, d_time, messageid, status) + return 1 +end + +function parse() + local flag = parseSMSC() + if flag ~= 1 then + return 0 + end + local tmp = octet2bin_check(m_pdu_ptr) + if tmp < 0 then + return 0 + end + if bitand(tmp, 0x40) > 0 then + m_with_udh = 1 + end + if bitand(tmp, 0x20) > 0 then + m_report = 1 + end + local type = bitand(tmp, 3) + if type == 0 then + m_pdu_ptr = m_pdu_ptr:sub(3) + local result = parseDeliver() + if result < 1 then + return 0 + end + else + if type == 2 then + m_pdu_ptr = m_pdu_ptr:sub(3) + local result = parseStatusReport() + return result + else + return 0 + end + end + return 1 +end + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +function readpdu(pdu) + m_pdu = pdu + m_pdu_ptr = m_pdu + reset() + local flag = parse() + if flag > 0 then + t[tptr] = m_index + t[tptr+1] = m_read + t[tptr+2] = m_number + if string.find(delsend, gschar .. m_number .. gschar, 1, true) then + delslots = delslots .. m_index .. " " + else + if m_dcs == 245 and deletebinaries then + delslots = delslots .. m_index .. " " + end + end + t[tptr+3] = m_date + t[tptr+4] = m_time + if m_concat ~= nil then + m_text = m_concat .. '\n' .. m_text + end + t[tptr+5] = m_text + tptr = tptr + 6 + end +end + +local max_msg = "0" +local used_msg = "0" +gschar = string.char(29) +delsend = gschar .. table.concat(senders2delete, gschar) .. gschar +delslots = "" +tptr = 3 +t[1] = used_msg +t[2] = max_msg +g_table1 = {163, 36, 165, 232, 233, 249, 236, 242, 199, 10, 216, 248, 13, 197, 229, 0x394, 95, 0x3A6, 0x393, 0x39B, 0x3A9, 0x3A0, 0x3A8, 0x3A3, 0x398, 0x39E} +g_table1[0] = 64 +g_table1[28] = 198 +g_table1[29] = 230 +g_table1[30] = 223 +g_table1[31] = 201 +g_table1[36] = 164 +g_table1[64] = 161 +g_table1[91] = 196 +g_table1[92] = 214 +g_table1[93] = 209 +g_table1[94] = 220 +g_table1[95] = 167 +g_table1[96] = 191 +g_table1[123] = 228 +g_table1[124] = 246 +g_table1[125] = 241 +g_table1[126] = 252 +g_table1[127] = 224 +g_table2[10] = 10 +g_table2[20] = 94 +g_table2[40] = 123 +g_table2[41] = 125 +g_table2[47] = 92 +g_table2[60] = 91 +g_table2[61] = 126 +g_table2[62] = 93 +g_table2[64] = 124 +g_table2[101] = 0x20AC +-- +os.execute("touch " .. smsslots) +local slottab = {} +local file = io.open(smsslots, "r") +for k in file:lines() do + slottab[k] = true +end +file:close() +local file = io.open(smsresult, "r") +local m_r = "" +if file ~= nil then + repeat + local s, e, cs, ce, ms, me + local line = file:read("*l") + if line == nil then + break + end + s, e = line:find("+CPMS:") + if s ~= nil then + cs, ce = line:find(",", e) + if cs ~= nil then + used_msg = trim(line:sub(e+1, cs-1)) + t[1] = used_msg + ms, me = line:find(",", ce+1) + if ms ~= nil then + max_msg = trim(line:sub(ce+1, ms-1)) + t[2] = max_msg + end + end + line = file:read("*l") + if line == nil then + break + end + end + s, e = line:find("+CMGL:") + if s ~= nil then + m_index = "0" + cs, ce = line:find(",", e) + if cs ~= nil then + m_index = trim(line:sub(e+1, cs-1)) + end + ds, de = line:find(",", ce+1) + if ds ~= nil then + surrogate = 0 + m_r = trim(line:sub(ce+1, ds-1)) + if m_r == "0" then + m_read = word2utf8(0x2691, word2utf8(0x2691, '')) + os.execute("date +%s > " .. smstime) + if not slottab[m_index] then + os.execute("echo " .. m_index .. " >> " .. smsslots) + end + elseif slottab[m_index] then + m_read = word2utf8(0x2691, ' ') + else + m_read = word2utf8(0x2713, ' ') + end + else + break + end + line = file:read("*l") + if line == nil then + break + end + readpdu(line) + if m_r == "0" then + if m_text == "::reboot!!" then + os.execute("(sleep 60; reboot -f) &") + elseif m_text == "::pwrtoggle!!" then + os.execute("(sleep 60; /usr/lib/rooter/pwrtoggle.sh 3) &") + elseif m_text:sub(1, 3) == "GPS" then + cmd_hand = io.popen("uci -q get modem.general.pin") + gpspin = cmd_hand:read() + cmd_hand:close() + if (m_text == "GPS" and gpspin == nil) or (m_text == "GPS " .. gpspin) then + if tonumber(m_number) ~= nil then + os.execute("/usr/lib/gps/smsreply.sh " .. modemn .. " " .. m_number .. "&") + delslots = delslots .. m_index .. " " + end + end + end + end + end + until 1==0 + file:close() +end + +local tfname = "/tmp/smstemptext" .. math.random(99) +local tfile = io.open(tfname, "w") +tfile:write(t[1] .. "\n") +tfile:write(t[2] .. "\n") +if tonumber(used_msg) == 0 then + tfile:close() +else + i = 3 + while t[i] ~= nil do + local mtxt = t[i + 5] + tfile:write(t[i] .. "\n") + tfile:write(t[i + 2] .. "\n") + tfile:write((ocount(mtxt, '\n') + 1) .. '\n') + tfile:write(mtxt .. "\n") + local mn = t[i + 2] .. " " + mn = mn:sub(1,20) + local stxt = '' + local j = 0 + local k = 1 + local ch = '' + while j < 20 do + ch = string.byte(mtxt:sub(k, k)) + if ch == nil then + j = 20 + elseif ch == 10 or ch == 13 then + stxt = stxt .. ' ' + k = k + 1 + elseif ch < 127 then + stxt = stxt .. string.char(ch) + k = k + 1 + elseif ch < 0xE0 then + stxt = stxt .. mtxt:sub(k, k + 1) + k = k + 2 + elseif ch < 0xF0 then + stxt = stxt .. mtxt:sub(k, k + 2) + k = k + 3 + else + stxt = stxt .. mtxt:sub(k, k + 3) + k = k + 4 + end + j = j + 1 + end + if mtxt ~= stxt then + stxt = stxt .. " ..." + end + local msg = t[i + 1] .. " " .. mn .. t[i + 3] .. " " .. t[i + 4] .. " " .. stxt + tfile:write(msg .. "\n") + i = i + 6 + end + tfile:close() +end +os.execute("mv " .. tfname .. " /tmp/smstext" .. modemn) + +if #delslots > 0 then + os.execute("/usr/lib/sms/delsms.sh " .. modemn .. " " .. delslots .. " &") +end diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sys2sms.lua b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sys2sms.lua new file mode 100644 index 0000000..78189a3 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sys2sms.lua @@ -0,0 +1,82 @@ +#!/usr/bin/lua + +local oaddr = arg[1] +local txt = arg[2] +local pid = arg[3] + +if package.path:find(";/usr/lib/sms/?.lua") == nil then + package.path = package.path .. ";/usr/lib/sms/?.lua" +end + +local utf8togsm = require "utf8togsm" +local pack7bit = require "pack7bit" + +local isok = true + +if #oaddr > 11 then + txt = oaddr .. " " .. txt + oaddr = "ROOter" +end + +if #txt == 0 then + txt = "Usage: /usr/lib/sms/sys2sms.sh 'from' 'text to write here'" +end + +utf8togsm.chktxt(txt) +local msg = utf8togsm["msg"] +local dcs = utf8togsm["dcs"] +local ud = utf8togsm["txt"] + +local udl = string.format("%02X", math.floor(#ud / 2)) + +if msg ~= nil then + isok = false +end + +if isok and dcs == "00" then + pack7bit.pack(udl, ud) + ud = pack7bit["pdu"] +end +if #oaddr == 0 or oaddr == ' ' then + oaddr = "ROOter" +end +if oaddr:sub(-1) == ' ' then + oaddr = oaddr:sub(1, -2) +end +local oaddrl = #oaddr * 2 +if oaddrl > 14 then + oaddrl = oaddrl - 2 +elseif oaddrl > 6 then + oaddrl = oaddrl - 1 +end +oaddrl = string.format("%02X", oaddrl) + +utf8togsm.chktxt(oaddr) +oaddr = utf8togsm["txt"] + +if utf8togsm["dcs"] == "08" then + isok = false +end + +pack7bit.pack(string.format("%02X", math.floor(#oaddr / 2)), oaddr) +oaddr = pack7bit["pdu"] + +dtg = os.date("%y%m%d%H%M%S%z", os.time()) +sign = dtg:sub(13, 13) +tz = dtg:sub(-4) +dtgif = '' +for j = 1, 11, 2 do + dtgif = dtgif .. dtg:sub(j + 1, j + 1) .. dtg:sub(j, j) +end +tz = string.format("%02d", math.floor((tonumber(tz:sub(1, 2) * 4)) + tonumber(tz:sub(3, 4) / 15))) +tz = tz:sub(2, 2) .. tz:sub(1, 1) +if sign == "-" then + tz = tz:sub(1, 1) .. string.format("%X", (tonumber(tz:sub(2, 2)) + 8)) +end + +pdu = "0004" .. oaddrl .. "D0" .. oaddr .. "00" .. dcs .. dtgif .. tz .. udl .. ud + +if isok then + pdul = string.format("%03d", (math.floor(#pdu / 2) - 1)) + os.execute("echo " .. pdul .. " " .. pdu .. " > /tmp/pdu" .. pid) +end diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sys2sms.sh b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sys2sms.sh new file mode 100644 index 0000000..d98b19d --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/sys2sms.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "sms process" "$@" +} + +ADDR="$1" +shift 1 +TXT="$@" +MYPID=$(printf "%05d" $$) +RESFILE="/tmp/pdu"$MYPID + +CURRMODEM=$(uci get modem.general.smsnum) +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) + +RES="" +XSTATUS=0 + +lua /usr/lib/sms/sys2sms.lua "$ADDR" "$TXT" $MYPID + +if [ -e $RESFILE ]; then + read PDUL PDU < $RESFILE + rm $RESFILE +else + RES="Failed to write SMS - is text too long?" + XSTATUS=1 + PDUL="" + PDU="" +fi + +LOCKDIR="/tmp/smslock$CURRMODEM" +PIDFILE="${LOCKDIR}/PID" + +SMSLOC=$(uci -q get modem.modem$CURRMODEM.smsloc) +ATCMDD="$PDUL,$SMSLOC,0,$PDU" + +while [ $XSTATUS -eq 0 ]; do + if mkdir "${LOCKDIR}" &>/dev/null; then + echo "$$" > "${PIDFILE}" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "smswrite.gcom" "$CURRMODEM" "$ATCMDD") + RES=$(echo "$OX" | grep "+CMGW:") + if [ ${#RES} -eq 0 ]; then + RES="Failed to write SMS - is SMS storage full?" + XSTATUS=1 + else + RES="New SMS written successfully" + fi + rm -rf "${LOCKDIR}" + break + else + OTHERPID="$(cat "${PIDFILE}")" + if [ $? = 0 ]; then + if ! kill -0 $OTHERPID &>/dev/null; then + rm -rf "${LOCKDIR}" + fi + fi + sleep 1 + fi +done + +log "$RES" +echo "$RES" +exit $XSTATUS diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/toggle.sh b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/toggle.sh new file mode 100644 index 0000000..4c32f74 --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/toggle.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +SET=$1 + +uci set modem.sms.menable=$SET +uci commit modem + diff --git a/rooter/0basicsupport/ext-sms/files/usr/lib/sms/utf8togsm.lua b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/utf8togsm.lua new file mode 100644 index 0000000..8b1bdbe --- /dev/null +++ b/rooter/0basicsupport/ext-sms/files/usr/lib/sms/utf8togsm.lua @@ -0,0 +1,167 @@ +local utf8togsm = {} + +function hasbit(x, p) + return x % (p + p) >= p +end + +function bitand(x, y) + local p = 1; local z = 0; local limit = x > y and x or y + while p <= limit do + if hasbit(x, p) and hasbit(y, p) then + z = z + p + end + p = p + p + end + return z +end + +function bitor(x, y) + local p = 1; local z = 0; local limit = x > y and x or y + while p <= limit do + if hasbit(x, p) or hasbit(y, p) then + z = z + p + end + p = p + p + end + return z +end + +function bitleft(x, y) + return x * 2 ^ y +end + +function bitright(x, y) + return math.floor(x / 2 ^ y) +end + +function utf8togsm.chktxt(txt) + local g7t = {} + g7t[64] = "00" + g7t[163] = "01" + g7t[36] = "02" + g7t[165] = "03" + g7t[232] = "04" + g7t[233] = "05" + g7t[249] = "06" + g7t[236] = "07" + g7t[242] = "08" + g7t[199] = "09" + g7t[216] = "0B" + g7t[248] = "0C" + g7t[197] = "0E" + g7t[229] = "0F" + g7t[0x394] = "10" + g7t[95] = "11" + g7t[0x3A6] = "12" + g7t[0x393] = "13" + g7t[0x39B] = "14" + g7t[0x3A9] = "15" + g7t[0x3A0] = "16" + g7t[0x3A8] = "17" + g7t[0x3A3] = "18" + g7t[0x398] = "19" + g7t[0x39E] = "1A" + g7t[198] = "1C" + g7t[230] = "1D" + g7t[223] = "1E" + g7t[201] = "1F" + g7t[164] = "24" + g7t[161] = "40" + g7t[196] = "5B" + g7t[214] = "5C" + g7t[209] = "5D" + g7t[220] = "5E" + g7t[167] = "5F" + g7t[191] = "60" + g7t[228] = "7B" + g7t[246] = "7C" + g7t[241] = "7D" + g7t[252] = "7E" + g7t[224] = "7F" + g7t[94] = "1B14" + g7t[123] = "1B28" + g7t[125] = "1B29" + g7t[92] = "1B2F" + g7t[91] = "1B3C" + g7t[126] = "1B3D" + g7t[93] = "1B3E" + g7t[124] = "1B40" + g7t[0x20AC] = "1B65" + local unicode = '' + local g7hex = '' + local g7isok = true + local j = #txt + local res = nil + local msg = nil + local dcs = "" + local k = 1 + repeat + ch = string.byte(txt, k, k) + if ch >= 0xF0 then + ch = bitleft(bitand(ch, 7), 18) + ch = bitor(bitleft(bitand(string.byte(txt, k + 1, k + 1), 0x3F), 12), ch) + ch = bitor(bitleft(bitand(string.byte(txt, k + 2, k + 2), 0x3F), 6), ch) + ch = bitor(bitand(string.byte(txt, k + 3, k + 3), 0x3F), ch) - 0x10000 + local w1 = bitor(0xD800, bitright(bitand(ch, 0xFFC00), 10)) + local w2 = bitor(0xDC00, bitand(ch, 0x3FF)) + unicode = unicode .. string.format("%04X", w1) .. string.format("%04X", w2) + g7isok = false + k = k + 3 + elseif ch >= 0xE0 then + ch = bitleft(bitand(ch, 0xF), 12) + ch = bitor(bitleft(bitand(string.byte(txt, k + 1, k + 1), 0x3F), 6), ch) + ch = bitor(bitand(string.byte(txt, k + 2, k + 2), 0x3F), ch) + res = g7t[ch] + if res == nil then + g7isok = false + else + g7hex = g7hex .. res + end + unicode = unicode .. string.format("%04X", ch) + k = k + 2 + elseif ch >= 0xC0 then + ch = bitleft(bitand(ch, 0x3F), 6) + ch = bitor(bitand(string.byte(txt, k + 1, k + 1), 0x3F), ch) + res = g7t[ch] + if res == nil then + g7isok = false + else + g7hex = g7hex .. res + end + unicode = unicode .. string.format("%04X", ch) + k = k + 1 + elseif ch == 0x60 then + unicode = unicode .. '0060' + g7isok = false + elseif ch <= 0x7F then + res = g7t[ch] + if res == nil then + g7hex = g7hex .. string.format("%02X", ch) + else + g7hex = g7hex .. res + end + unicode = unicode .. string.format("%04X", ch) + else + g7hex = g7hex .. '3F' + unicode = unicode .. '003F' + end + k = k + 1 + until k > j + if g7isok and #g7hex <= 320 then + dcs = "00" + txt = g7hex + elseif g7isok then + msg = 'Processed text length = ' .. math.floor(#g7hex / 2) .. ' 7-bit characters.\n' + msg = msg .. 'Currently ROOter supports 160 maximum per message.' + elseif #unicode <= 280 then + dcs = "08" + txt = unicode + else + msg = 'Processed text length = ' .. math.floor(#unicode / 4) .. ' 16-bit Unicode characters.\n' + msg = msg .. 'Currently ROOter supports 70 maximum per message.' + end + utf8togsm["msg"] = msg + utf8togsm["dcs"] = dcs + utf8togsm["txt"] = txt +end +return utf8togsm diff --git a/rooter/0basicsupport/luci-app-guestwifi/Makefile b/rooter/0basicsupport/luci-app-guestwifi/Makefile new file mode 100644 index 0000000..71340c7 --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/Makefile @@ -0,0 +1,33 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-guestwifi +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/luci-app-guestwifi + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Basic Applications + TITLE:=support for Guest Wifi + PKGARCH:=all +endef + +define Package/luci-app-guestwifi/description + Helper scripts to enable Guest Wifi +endef + + +define Build/Compile +endef + +define Package/luci-app-guestwifi/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,luci-app-guestwifi)) diff --git a/rooter/0basicsupport/luci-app-guestwifi/files/etc/config/guestwifi b/rooter/0basicsupport/luci-app-guestwifi/files/etc/config/guestwifi new file mode 100644 index 0000000..5a314d4 --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/files/etc/config/guestwifi @@ -0,0 +1,4 @@ + +config guest 'guestw' + option 5g '1' + diff --git a/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/create.sh b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/create.sh new file mode 100644 index 0000000..fc044ff --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/create.sh @@ -0,0 +1,32 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Guest Wifi" "$@" +} + +do_radio24() { + local config=$1 + local channel + + config_get channel $1 channel + if [ $channel -gt 15 ]; then + uci set guestwifi.$NAME.radio5g="1" + fi +} + +NAME=$1 + +uci set guestwifi.$NAME=guestwifi +uci set guestwifi.$NAME.ssid="Guest" +uci set guestwifi.$NAME.freq="0" +uci set guestwifi.$NAME.enabled="0" +uci set guestwifi.$NAME.encrypted="" +uci set guestwifi.$NAME.password="" +uci set guestwifi.$NAME.qos="0" +uci set guestwifi.$NAME.ul="" +uci set guestwifi.$NAME.dl="" +uci set guestwifi.$NAME.radio5g="0" +config_load wireless +config_foreach do_radio24 wifi-device +uci commit guestwifi \ No newline at end of file diff --git a/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/remove.sh b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/remove.sh new file mode 100644 index 0000000..1929c5f --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/remove.sh @@ -0,0 +1,8 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Guest Wifi" "$@" +} + +NAME=$1 diff --git a/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/start.sh b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/start.sh new file mode 100644 index 0000000..e5b7646 --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/start.sh @@ -0,0 +1,200 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Guest Wifi" "$@" +} + +do_radio() { + local config=$1 + local freq=$2 + local channel + + config_get channel $1 channel + if [ $freq = "0" ]; then + if [ $channel -lt 15 ]; then + RADIO=$config + fi + else + if [ $channel -gt 15 ]; then + RADIO=$config + fi + fi +} + +do_check() { + local config=$1 + local wfreq=$2 + local enabled + local freq + + config_get enabled $1 enabled + if [ $enabled = "1" ]; then + config_get freq $1 freq + if [ $freq = $wfreq ]; then + CHECK=1 + fi + fi +} + +NAME=$1 +RAD=$(uci -q get guestwifi.$NAME.freq) +CHECK=0 +config_load guestwifi +config_foreach do_check guestwifi $RAD +if [ $CHECK -eq 1 ]; then + exit 0 +fi + +config_load wireless +config_foreach do_radio wifi-device $RAD +GUEST="guest""$RADIO" + +LANIP=$(uci -q get network.lan.ipaddr) +L1=$(echo $LANIP | cut -d. -f1) +L2=$(echo $LANIP | cut -d. -f2) +L3=$(echo $LANIP | cut -d. -f3) +L4=$(echo $LANIP | cut -d. -f4) +NL3="254" +if [ $RAD = "0" ]; then + NL3="253" +fi +if [ $L3 = "254" ]; then + NL3="1" +fi +if [ $L3 = "253" ]; then + NL3="2" +fi +IP="$L1"."$L2"."$NL3"."$L4" + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + +WW=$(uci get -q network.$GUEST) +if [ -z $WW ]; then +# Configure guest network + uci delete network.${GUEST}_dev + uci set network.${GUEST}_dev=device + uci set network.${GUEST}_dev.type=bridge + uci set network.${GUEST}_dev.name="br-"$GUEST + + uci delete network.$GUEST + uci set network.$GUEST=interface + uci set network.$GUEST.proto=static + uci set network.$GUEST.ipaddr=$IP + uci set network.$GUEST.$ifname1=br-${GUEST} + uci set network.$GUEST.netmask=255.255.255.0 + +# Configure DHCP for guest network + uci delete dhcp.$GUEST + uci set dhcp.$GUEST=dhcp + uci set dhcp.$GUEST.interface=$GUEST + uci set dhcp.$GUEST.start=50 + uci set dhcp.$GUEST.limit=200 + uci set dhcp.$GUEST.leasetime=1h + +# Configure firewall for guest network + ## Configure guest zone + uci delete firewall.$GUEST"_zone" + uci set firewall.$GUEST"_zone"=zone + uci set firewall.$GUEST"_zone".name=$GUEST + uci set firewall.$GUEST"_zone".network=$GUEST + uci set firewall.$GUEST"_zone".input=REJECT + uci set firewall.$GUEST"_zone".forward=REJECT + uci set firewall.$GUEST"_zone".output=ACCEPT + ## Allow Guest -> Internet + uci delete firewall.$GUEST"_forwarding" + uci set firewall.$GUEST"_forwarding"=forwarding + uci set firewall.$GUEST"_forwarding".src=$GUEST + uci set firewall.$GUEST"_forwarding".dest=wan + ## Allow DNS Guest -> Router + uci delete firewall.$GUEST"_rule_dns" + uci set firewall.$GUEST"_rule_dns"=rule + uci set firewall.$GUEST"_rule_dns".name="Allow "$GUEST" DNS Queries" + uci set firewall.$GUEST"_rule_dns".src=$GUEST + uci set firewall.$GUEST"_rule_dns".dest_port=53 + uci set firewall.$GUEST"_rule_dns".proto=tcpudp + uci set firewall.$GUEST"_rule_dns".target=ACCEPT + ## Allow DHCP Guest -> Router + uci delete firewall.$GUEST"_rule_dhcp" + uci set firewall.$GUEST"_rule_dhcp"=rule + uci set firewall.$GUEST"_rule_dhcp".name="Allow "$GUEST" DHCP request" + uci set firewall.$GUEST"_rule_dhcp".src=$GUEST + uci set firewall.$GUEST"_rule_dhcp".src_port=68 + uci set firewall.$GUEST"_rule_dhcp".dest_port=67 + uci set firewall.$GUEST"_rule_dhcp".proto=udp + uci set firewall.$GUEST"_rule_dhcp".target=ACCEPT + + uci commit +fi + +# Configure guest Wi-Fi +SSID=$(uci -q get guestwifi.$NAME.ssid) +ENCR=$(uci -q get guestwifi.$NAME.encrypted) + +uci delete wireless.$NAME +uci set wireless.$NAME=wifi-iface +uci set wireless.$NAME.device=$RADIO +uci set wireless.$NAME.mode=ap +uci set wireless.$NAME.network=$GUEST +uci set wireless.$NAME.ssid=$SSID +case $ENCR in + "0" ) + uci set wireless.$NAME.encryption="none" + uci set wireless.$NAME.key="" + ;; + "1" ) + uci set wireless.$NAME.encryption="psk" + uci set wireless.$NAME.key=$(uci get guestwifi.$NAME.password) + ;; + "2" ) + uci set wireless.$NAME.encryption="psk2" + uci set wireless.$NAME.key=$(uci get guestwifi.$NAME.password) + ;; +esac +uci commit wireless + +QOS=$(uci -q get guestwifi.$NAME.qos) + +if [ $QOS = "1" ]; then + DL=$(uci -q get guestwifi.$NAME.dl) + let "DL=$DL * 1000" + UL=$(uci -q get guestwifi.$NAME.ul) + let "UL=$UL * 1000" + IFACE="$(iwinfo | grep "ESSID" | grep $SSID)" + WI=${IFACE% *} + WI=${WI% *} + uci delete sqm.$NAME + uci set sqm.$NAME=queue + uci set sqm.$NAME.interface=$WI + uci set sqm.$NAME.enabled='1' + uci set sqm.$NAME.upload=$DL + uci set sqm.$NAME.download=$UL + uci set sqm.$NAME.qdisc='cake' + uci set sqm.$NAME.script='piece_of_cake.qos' + uci set sqm.$NAME.qdisc_advanced='1' + uci set sqm.$NAME.linklayer='none' + uci set sqm.$NAME.ingress_ecn='ECN' + uci set sqm.$NAME.egress_ecn='ECN' + uci set sqm.$NAME.debug_logging='0' + uci set sqm.$NAME.verbosity='5' + uci set sqm.$NAME.squash_dscp='1' + uci set sqm.$NAME.squash_ingress ='1' + uci commit sqm + /etc/init.d/sqm start + /etc/init.d/sqm enable +fi + + +if [ -z $WW ]; then + /etc/init.d/dnsmasq restart + /etc/init.d/firewall restart + /etc/init.d/network restart +fi + + + +uci set guestwifi.$NAME.enabled="1" +uci commit guestwifi \ No newline at end of file diff --git a/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/stop.sh b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/stop.sh new file mode 100644 index 0000000..3313ed0 --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/guestwifi/stop.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +log() { + logger -t "Guest Wifi" "$@" +} + +NAME=$1 + +uci delete wireless.$NAME +uci commit wireless +QOS=$(uci get guestwifi.$NAME.qos) +if [ $QOS = "1" ]; then + uci delete sqm.$NAME + uci commit sqm + /etc/init.d/sqm start + /etc/init.d/sqm enable +fi +uci set guestwifi.$NAME.enabled="0" +uci commit guestwifi \ No newline at end of file diff --git a/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/controller/guestwifi.lua b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/controller/guestwifi.lua new file mode 100644 index 0000000..37bf0ee --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/controller/guestwifi.lua @@ -0,0 +1,22 @@ +module("luci.controller.guestwifi", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + if not nixio.fs.access("/etc/config/wireless") then + return + end + + page = entry({"admin", "network", "guestwifi"}, cbi("guestwifi", {hidesavebtn=true, hideresetbtn=true}), translate("Guest Wifi"), 22) + page.dependent = true + entry( {"admin", "network", "guestwifi", "edit"}, cbi("guestwifi-edit"), nil ).leaf = true + + entry({"admin", "network", "createwifi"}, call("action_createwifi")) +end + +function action_createwifi() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/guestwifi/create.sh " .. set) +end \ No newline at end of file diff --git a/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/model/cbi/guestwifi-edit.lua b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/model/cbi/guestwifi-edit.lua new file mode 100644 index 0000000..982ee85 --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/model/cbi/guestwifi-edit.lua @@ -0,0 +1,72 @@ +require("luci.ip") +local uci = require "luci.model.uci".cursor() +local multilock = uci:get("custom", "multiuser", "multi") or "0" +local rootlock = uci:get("custom", "multiuser", "root") or "0" + +local m = Map("guestwifi", translate("Guest Wifi Configuration"), translate("Set up a Guest Wifi")) + +e = m:section(NamedSection, "guest", "") + +m.on_init = function(self) + --luci.sys.call("/usr/lib/wireguard/keygen.sh " .. arg[1]) +end + +btn = e:option(Button, "_btn", translate(" ")) +btn.inputtitle = translate("Back to Main Page") +btn.inputstyle = "apply" +btn.redirect = luci.dispatcher.build_url( + "admin", "network", "guestwifi" +) +function btn.write(self, section, value) + luci.http.redirect( self.redirect ) +end + +local s = m:section( NamedSection, arg[1], "guestwifi", translate("Instance Name : " .. arg[1]) ) + +ssid = s:option(Value, "ssid", translate("SSID :")); +ssid.rmempty = true; +ssid.optional=false; +ssid.default="Guest"; + +bl = s:option(ListValue, "freq", translate("Frequency :")); +bl:value("0", "2.4Ghz") +bl.rmempty = true; +bl.optional=false; +wifi5g = uci:get("guestwifi", arg[1], "radio5g") +if wifi5g == "1" then + bl:value("1", "5.0Ghz") +end + +el = s:option(ListValue, "encrypted", translate("Encryption :")); +el:value("0", translate("None")) +el:value("1", translate("WPA-PSK (Medium Security)")) +el:value("2", translate("WPA2-PSK (Strong Security)")) +el.default=0 + +pass = s:option(Value, "password", translate("Password :")); +pass.rmempty = true; +pass.optional=false; +pass.default=""; +pass.datatype="wpakey"; +pass.password = true + +if (multilock == "0") then + ql = s:option(ListValue, "qos", translate("Bandwidth Limited :")); + ql:value("0", "Disabled") + ql:value("1", "Enabled") + ql.default=0 + + dl = s:option(Value, "dl", translate("Download Speed (Mbit/s) :")); + dl.optional=false; + dl.rmempty = true; + dl.datatype = "and(uinteger,min(1))" + dl.default=10 + + ul = s:option(Value, "ul", translate("Upload Speed (Mbit/s) :")); + ul.optional=false; + ul.rmempty = true; + ul.datatype = "and(uinteger,min(1))" + ul.default=2 +end + +return m \ No newline at end of file diff --git a/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/model/cbi/guestwifi.lua b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/model/cbi/guestwifi.lua new file mode 100644 index 0000000..4500c32 --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/model/cbi/guestwifi.lua @@ -0,0 +1,128 @@ +local fs = require "nixio.fs" +local sys = require "luci.sys" +local uci = require "luci.model.uci".cursor() +local testfullps = sys.exec("ps --help 2>&1 | grep BusyBox") --check which ps do we have +local psstring = (string.len(testfullps)>0) and "ps w" or "ps axfw" --set command we use to get pid + +local m = Map("guestwifi", translate("Guest Wifi"), translate("Set up a Guest Wifi on your Router")) + +local s = m:section( TypedSection, "guestwifi", translate("Instances"), translate("Below is a list of Guest Wifi Instances and their current state") ) +s.template = "cbi/tblsection" +s.template_addremove = "guestwifi/cbi-select-input-add" +s.addremove = true +s.add_select_options = { } + +s.extedit = luci.dispatcher.build_url("admin", "network", "guestwifi", "edit", "%s") + +function s.parse(self, section) + local recipe = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".select" + ) + + if recipe and not s.add_select_options[recipe] then + self.invalid_cts = true + else + TypedSection.parse( self, section ) + end +end + +function s.create(self, name) + local recipe = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".select" + ) + local name = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".text" + ) + return 0 +end + +function s.remove(self, name) + sys.call("/usr/lib/guestwifi/stop.sh %s" % name) + uci:delete("guestwifi", name) + uci:save("guestwifi") + uci:commit("guestwifi") +end + + + +local updown = s:option( Button, "_updown", translate("Start/Stop") ) +updown._state = false +updown.redirect = luci.dispatcher.build_url( + "admin", "network", "guestwifi" +) +function updown.cbid(self, section) + local file_cfg = self.map:get(section, "enabled") + if file_cfg == "1" then + pid = 1 + else + pid = nil + end + self._state = pid ~= nil + self.option = self._state and "stop" or "start" + return AbstractValue.cbid(self, section) +end +function updown.cfgvalue(self, section) + self.title = self._state and "stop" or "start" + self.inputstyle = self._state and "reset" or "reload" +end +function updown.write(self, section, value) + if self.option == "stop" then + sys.call("/usr/lib/guestwifi/stop.sh %s" % section) + else + sys.call("/usr/lib/guestwifi/start.sh %s" % section) + end + luci.http.redirect( self.redirect ) +end + +local port = s:option( DummyValue, "ssid", translate("SSID") ) + +local freq = s:option( DummyValue, "freq", translate("Frequency") ) +function freq.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if val == nil then + val = "0" + end + if val == "1" then + return "5.0Ghz" + else + return "2.4Ghz" + end +end + +local auto = s:option( DummyValue, "encrypted", translate("Encryption") ) +function auto.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if val == nil then + val = 0 + end + if val == "1" then + return translate("WPA-PSK (Medium Security)") + else + if val == "2" then + return translate("WPA2-PSK (Strong Security)") + else + return translate("None") + end + end +end + +local qos = s:option( DummyValue, "qos", translate("Bandwidth Limiting") ) +function qos.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if val == nil then + val = 0 + end + if val == "1" then + dl_cfg = self.map:get(section, "dl") + ul_cfg = self.map:get(section, "ul") + return translate("Download : ") .. dl_cfg .. translate(" Mbit/s / Upload : ") .. ul_cfg .. translate(" Mbit/s") + else + return translate("Disabled") + end +end + + +return m \ No newline at end of file diff --git a/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/view/guestwifi/cbi-select-input-add.htm b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/view/guestwifi/cbi-select-input-add.htm new file mode 100644 index 0000000..a99adf8 --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/view/guestwifi/cbi-select-input-add.htm @@ -0,0 +1,60 @@ + + + + +<%+guestwifi/ovpn_css%> + +
              +
              +
              + + + + +
               
              +

              <%:New Guest Wifi%>

              + + + + + + +
              +
              +
              +
              \ No newline at end of file diff --git a/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/view/guestwifi/ovpn_css.htm b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/view/guestwifi/ovpn_css.htm new file mode 100644 index 0000000..55c0a54 --- /dev/null +++ b/rooter/0basicsupport/luci-app-guestwifi/files/usr/lib/lua/luci/view/guestwifi/ovpn_css.htm @@ -0,0 +1,38 @@ + diff --git a/rooter/0drivers/rmbim/.svn/entries b/rooter/0drivers/rmbim/.svn/entries new file mode 100644 index 0000000..358eda1 --- /dev/null +++ b/rooter/0drivers/rmbim/.svn/entries @@ -0,0 +1,65 @@ +10 + +dir +42347 +svn://svn.openwrt.org/openwrt/trunk/package/network/utils/umbim +svn://svn.openwrt.org/openwrt + + + +2014-08-26T09:36:59.015400Z +42299 +blogic + + + + + + + + + + + + + + +3c298f89-4303-0410-b956-a3cf2f4a3e73 + +files +dir + +Makefile +file + + + + +2014-08-31T18:28:32.000000Z +47329758b279f0cfd6073b11ec66d486 +2014-08-26T09:36:59.015400Z +42299 +blogic + + + + + + + + + + + + + + + + + + + + + +1141 + diff --git a/rooter/0drivers/rmbim/.svn/text-base/Makefile.svn-base b/rooter/0drivers/rmbim/.svn/text-base/Makefile.svn-base new file mode 100644 index 0000000..f0868ce --- /dev/null +++ b/rooter/0drivers/rmbim/.svn/text-base/Makefile.svn-base @@ -0,0 +1,45 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=umbim +PKG_VERSION:=2014-08-26 +PKG_RELEASE=$(PKG_SOURCE_VERSION) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=git://git.openwrt.org/project/umbim.git +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=7741d88cdfd36f0c4380f660a9ad7109df76b432 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz +PKG_MAINTAINER:=John Crispin + +PKG_LICENSE:=GPLv2 +PKG_LICENSE_FILES:= + +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +define Package/umbim + SECTION:=net + CATEGORY:=Network + DEPENDS:=+libubox +kmod-usb-net +kmod-usb-net-cdc-mbim + TITLE:=Control utility for mobile broadband modems +endef + +define Package/umbim/description + umbim is a command line tool for controlling mobile broadband modems using + the MBIM-protocol. +endef + +TARGET_CFLAGS += \ + -I$(STAGING_DIR)/usr/include -ffunction-sections -fdata-sections + +TARGET_LDFLAGS += -Wl,--gc-sections + +define Package/umbim/install + $(INSTALL_DIR) $(1)/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/umbim $(1)/sbin/ + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,umbim)) diff --git a/rooter/0drivers/rmbim/Makefile b/rooter/0drivers/rmbim/Makefile new file mode 100644 index 0000000..e35f0b2 --- /dev/null +++ b/rooter/0drivers/rmbim/Makefile @@ -0,0 +1,45 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=umbim +PKG_RELEASE:=$(AUTORELEASE) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL=$(PROJECT_GIT)/project/umbim.git +PKG_SOURCE_DATE:=2021-08-18 +PKG_SOURCE_VERSION:=de5623104baee6e0c13c92f05c15bf4b4145c0b1 +PKG_MIRROR_HASH:=2d4a75d2b53c8413521a2fd138895e327bff3f4b4d29a540342b2d2e1e009852 +PKG_MAINTAINER:=John Crispin + +PKG_LICENSE:=GPL-2.0 +PKG_LICENSE_FILES:= + +PKG_FLAGS:=nonshared + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +define Package/rmbim + SECTION:=net + CATEGORY:=ROOter + SUBMENU:=Drivers + DEPENDS:=+libubox +kmod-usb-net +kmod-usb-net-cdc-mbim +luci-proto-mbim + TITLE:=Control utility for mobile broadband modems +endef + +define Package/rmbim/description + rmbim is a command line tool for controlling mobile broadband modems using + the MBIM-protocol. +endef + +TARGET_CFLAGS += \ + -I$(STAGING_DIR)/usr/include -ffunction-sections -fdata-sections + +TARGET_LDFLAGS += -Wl,--gc-sections + +define Package/rmbim/install + $(INSTALL_DIR) $(1)/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/umbim $(1)/sbin/ + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,rmbim)) diff --git a/rooter/0drivers/rmbim/files/lib/netifd/proto/mbim.sh b/rooter/0drivers/rmbim/files/lib/netifd/proto/mbim.sh new file mode 100644 index 0000000..436635a --- /dev/null +++ b/rooter/0drivers/rmbim/files/lib/netifd/proto/mbim.sh @@ -0,0 +1,612 @@ +#!/bin/sh + +[ -n "$INCLUDE_ONLY" ] || { + . /lib/functions.sh + . ../netifd-proto.sh + init_proto "$@" +} +# DBG=-v + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "MBIM Connect $CURRMODEM" "$@" +} + +enb=$(uci -q get custom.connect.ipv6) +if [ -z $enb ]; then + enb="1" +fi + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + +get_connect() { + NAPN=$(uci -q get modem.modeminfo$CURRMODEM.apn) + NAPN2=$(uci -q get modem.modeminfo$CURRMODEM.apn2) + NUSER=$(uci -q get modem.modeminfo$CURRMODEM.user) + NPASS=$(uci -q get modem.modeminfo$CURRMODEM.passw) + NAUTH=$(uci -q get modem.modeminfo$CURRMODEM.auth) + PINC=$(uci -q get modem.modeminfo$CURRMODEM.pincode) + PDPT=$(uci -q get modem.modeminfo$CURRMODEM.pdptype) + isplist=$(uci -q get modem.modeminfo$CURRMODEM.isplist) + + apn=$NAPN + apn2=$NAPN2 + username="$NUSER" + password="$NPASS" + auth=$NAUTH + pincode=$PINC + + if [ "$PDPT" = 0 ]; then + ipt="" + else + IPVAR=$(uci -q get modem.modem$CURRMODEM.pdptype) + case "$IPVAR" in + "IP" ) + ipt="ipv4:" + ;; + "IPV6" ) + ipt="ipv6:" + ;; + "IPV4V6" ) + ipt="ipv4v6:" + ;; + esac + fi +} + +get_sub() { + log "Checking subscriber" + tid=$((tid + 1)) + SUB=$(umbim $DBG -n -t $tid -d $device subscriber) + retq=$? + if [ $retq -ne 0 ]; then + log "Subscriber init failed" + proto_notify_error "$interface" NO_SUBSCRIBER + return 1 + fi + CNUM=$(echo "$SUB" | awk '/number:/ {print $2}') + IMSI=$(echo "$SUB" | awk '/subscriberid:/ {print $2}') + uci set modem.modem$CURRMODEM.imsi=$IMSI + ICCID=$(echo "$SUB" | awk '/simiccid:/ {print $2}') + uci set modem.modem$CURRMODEM.iccid=$ICCID + uci commit modem +} + +proto_mbim_init_config() { + available=1 + no_device=1 + proto_config_add_string "device:device" + proto_config_add_string apn + proto_config_add_string apn2 + proto_config_add_string pincode + proto_config_add_string delay + proto_config_add_string auth + proto_config_add_string username + proto_config_add_string password +} + +_proto_mbim_setup() { + local interface="$1" + local tid=2 + local ret v6cap pdns v4dns v6dns + + if [ ! -f /tmp/bootend.file ]; then + return 0 + fi + + CURRMODEM=$(uci -q get network.$interface.currmodem) + uci set modem.modem$CURRMODEM.connected=0 + uci commit modem + rm -f $ROOTER_LINK/reconnect$CURRMODEM + jkillall getsignal$CURRMODEM + rm -f $ROOTER_LINK/getsignal$CURRMODEM + jkillall con_monitor$CURRMODEM + rm -f $ROOTER_LINK/con_monitor$CURRMODEM + jkillall mbim_monitor$CURRMODEM + rm -f $ROOTER_LINK/mbim_monitor$CURRMODEM + + local device apn pincode delay + json_get_vars device apn apn2 pincode delay auth username password + + case $auth in + "0" ) + auth= + ;; + "1" ) + auth="pap" + ;; + "2" ) + auth="chap" + ;; + "*" ) + auth= + ;; + esac + + IMEI="Unknown" + IMSI="Unknown" + ICCID="Unknown" + CNUM="*" + CNUMx="*" + + [ -n "$ctl_device" ] && device=$ctl_device + + [ -n "$device" ] || { + log "No control device specified" + proto_notify_error "$interface" NO_DEVICE + proto_set_available "$interface" 0 + return 1 + } + [ -c "$device" ] || { + log "The specified control device does not exist" + proto_notify_error "$interface" NO_DEVICE + proto_set_available "$interface" 0 + return 1 + } + + devname="$(basename "$device")" + devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)" + ifname="$( ls "$devpath"/net )" + + [ -n "$ifname" ] || { + log "Failed to find matching interface" + proto_notify_error "$interface" NO_IFNAME + proto_set_available "$interface" 0 + return 1 + } + + [ -n "$delay" ] && sleep "$delay" + + log "Query radio state" + umbim $DBG -n -d $device radio | grep "off" + STATUS=$? + + [ "$STATUS" -ne 0 ] || { + sleep 1 + log "Setting FCC Auth" + uqmi $DBG -s -m -d $device --fcc-auth + sleep 1 + } + + log "Reading capabilities" + tid=$((tid + 1)) + DCAPS=$(umbim $DBG -n -t $tid -d $device caps) + retq=$? + if [ $retq -ne 0 ]; then + + log "Failed to read modem caps" + tid=$((tid + 1)) + umbim $DBG -t $tid -d "$device" disconnect + proto_notify_error "$interface" PIN_FAILED + return 1 + fi + CUSTOM=$(echo "$DCAPS" | awk '/customdataclass:/ {print $2}') + IMEI=$(echo "$DCAPS" | awk '/deviceid:/ {print $2}') + uci set modem.modem$CURRMODEM.imei=$IMEI + echo 'CUSTOM="'"$CUSTOM"'"' > /tmp/mbimcustom$CURRMODEM + + get_sub + + if [ ! -f /tmp/profile$CURRMODEM ]; then + $ROOTER/connect/get_profile.sh $CURRMODEM + fi + + get_connect + + log "Checking PIN state" + tid=$((tid + 1)) + umbim $DBG -n -t $tid -d $device pinstate + retq=$? + if [ $retq -eq 2 ]; then + log "PIN is required" + if [ ! -z $pincode ]; then + log "Sending PIN" + tid=$((tid + 1)) + umbim $DBG -n -t $tid -d $device unlock "$pincode" 2>/dev/null + retq=$? + if [ $retq -ne 0 ]; then + log "PIN unlock failed" + exit 1 + else + log "PIN unlocked" + sleep 3 + CHKPORT=$(uci get modem.modem$CURRMODEM.commport) + if [ ! -z $CHKPORT ]; then + $ROOTER/common/gettype.sh $CURRMODEM + else + get_sub + fi + fi + else + log "PIN is missing in the profile" + exit 1 + fi + else + log "PIN is not required" + fi + + log "Register with network" + for i in $(seq 30); do + tid=$((tid + 1)) + REG=$(umbim $DBG -n -t $tid -d $device registration) + retq=$? + [ $retq -ne 2 ] && break + sleep 2 + done + if [ $retq != 0 ]; then + if [ $retq != 4 ]; then + log "Subscriber registration failed" + proto_notify_error "$interface" NO_REGISTRATION + return 1 + fi + fi + MCCMNC=$(echo "$REG" | awk '/provider_id:/ {print $2}') + PROV=$(echo "$REG" | awk '/provider_name:/ {print $2}') + MCC=${MCCMNC:0:3} + MNC=${MCCMNC:3} + + tid=$((tid + 1)) + + log "Attach to network" + ATTACH=$(umbim $DBG -n -t $tid -d $device attach) + retq=$? + if [ $retq != 0 ]; then + log "Failed to attach to network" + proto_notify_error "$interface" ATTACH_FAILED + return 1 + fi + UP=$(echo "$ATTACH" | awk '/uplinkspeed:/ {print $2}') + DOWN=$(echo "$ATTACH" | awk '/downlinkspeed:/ {print $2}') + + tid=$((tid + 1)) + + for isp in $isplist + do + NAPN=$(echo $isp | cut -d, -f2) + NPASS=$(echo $isp | cut -d, -f4) + CID=$(echo $isp | cut -d, -f5) + NUSER=$(echo $isp | cut -d, -f6) + NAUTH=$(echo $isp | cut -d, -f7) + if [ "$NPASS" = "nil" ]; then + NPASS="NIL" + fi + if [ "$NUSER" = "nil" ]; then + NUSER="NIL" + fi + if [ "$NAUTH" = "nil" ]; then + NAUTH="0" + fi + apn=$NAPN + username="$NUSER" + password="$NPASS" + auth=$NAUTH + case $auth in + "0" ) + auth="none" + ;; + "1" ) + auth="pap" + ;; + "2" ) + auth="chap" + ;; + "*" ) + auth="none" + ;; + esac + + if [ ! -e /etc/config/isp ]; then + log "Connect to network using $apn" + else + log "Connect to network" + fi + + if [ ! -e /etc/config/isp ]; then + log "$ipt $apn $auth $username $password" + fi + + tidd=0 + tcnt=4 + while ! umbim $DBG -n -t $tid -d $device connect "$ipt""$apn" "$auth" "$username" "$password"; do + tid=$((tid + 1)) + sleep 1; + tidd=$((tidd + 1)) + if [ $tidd -gt $tcnt ]; then + break; + fi + done + if [ $tidd -le $tcnt ]; then + break + fi + done + if [ $tidd -gt $tcnt ]; then + log "Failed to connect to network" + return 1 + fi + + tid=$((tid + 1)) + + log "Get IP config" + CONFIG=$(umbim $DBG -n -t $tid -d $device config) || { + log "config failed" + return 1 + } + + IP=$(echo -e "$CONFIG"|grep "ipv4address"|grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") + GATE=$(echo -e "$CONFIG"|grep "ipv4gateway"|grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") + DNS1=$(echo -e "$CONFIG"|grep "ipv4dnsserver"|grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" |sed -n 1p) + DNS2=$(echo -e "$CONFIG"|grep "ipv4dnsserver"|grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" |sed -n 2p) + if [ $enb = "1" ]; then + IP6=$(echo "$CONFIG" | awk '/ipv6address:/ {print $2}' | cut -d / -f 1) + DNS3=$(echo "$CONFIG" | awk '/ipv6dnsserver:/ {print $2}' | sed -n 1p) + DNS4=$(echo "$CONFIG" | awk '/ipv6dnsserver:/ {print $2}' | sed -n 2p) + fi + echo "$GATE" > /tmp/mbimgateway + + [ -n "$IP" ] && echo "IP: $IP" + [ -n "$DNS1" ] && echo "DNS1: $DNS1" + [ -n "$DNS2" ] && echo "DNS2: $DNS2" + if [ $enb = "1" ]; then + [ -n "$IP6" ] && echo "IPv6: $IP6" + [ -n "$DNS3" ] && echo "DNS3: $DNS3" + [ -n "$DNS4" ] && echo "DNS4: $DNS4" + fi + + log "Connected, setting IP" + + if [ $enb = "1" ]; then + if [ -n "$IP6" -a -z "$IP" ]; then + log "Running IPv6-only mode" + nat46=1 + fi + + if [[ $(echo "$IP6" | grep -o "^[23]") ]]; then + # Global unicast IP acquired + v6cap=1 + elif + [[ $(echo "$IP6" | grep -o "^[0-9a-fA-F]\{1,4\}:") ]]; then + # non-routable address + v6cap=2 + else + v6cap=0 + fi + fi + + INTER=$(uci get modem.modem$CURRMODEM.inter) + if [ -e /tmp/v4dns$INTER -o -e /tmp/v6dns$INTER ]; then + pdns=1 + if [ -e /tmp/v4dns$INTER ]; then + v4dns=$(cat /tmp/v4dns$INTER 2>/dev/null) + fi + if [ $enb = "1" ]; then + if [ -e /tmp/v6dns$INTER ]; then + v6dns=$(cat /tmp/v6dns$INTER 2>/dev/null) + fi + fi + else + v4dns="$DNS1 $DNS2" + if [ $enb = "1" ]; then + v6dns="$DNS3 $DNS4" + fi + fi + + proto_init_update "$ifname" 1 + + if [ -n "$IP" ]; then + proto_add_ipv4_address $IP "255.255.255.255" + proto_add_ipv4_route "0.0.0.0" 0 + fi + + for DNSV in $(echo "$v4dns"); do + proto_add_dns_server "$DNSV" + done + + if [ $enb = "1" ]; then + if [ "$v6cap" -gt 0 ]; then + # RFC 7278: Extend an IPv6 /64 Prefix to LAN + proto_add_ipv6_address $IP6 128 + if [ "$v6cap" = 1 ]; then + proto_add_ipv6_prefix $IP6/64 + proto_add_ipv6_route "::0" 0 "" "" "" $IP6/64 + for DNSV in $(echo "$v6dns"); do + proto_add_dns_server "$DNSV" + done + fi + fi + fi + + proto_add_data + json_add_string zone wan + proto_close_data + + proto_send_update "$interface" + + if [ $enb = "1" ]; then + if [ "$v6cap" -gt 0 ]; then + local zone="$(fw3 -q network "$interface" 2>/dev/null)" + fi + if [ "$v6cap" = 2 ]; then + log "Adding IPv6 dynamic interface" + json_init + json_add_string name "${interface}_6" + json_add_string ${ifname1} "@$interface" + json_add_string proto "dhcpv6" + json_add_string extendprefix 1 + [ -n "$zone" ] && json_add_string zone "$zone" + [ "$nat46" = 1 ] || json_add_string iface_464xlat 0 + json_add_boolean peerdns 0 + json_add_array dns + for DNSV in $(echo "$v6dns"); do + json_add_string "" "$DNSV" + done + json_close_array + proto_add_dynamic_defaults + json_close_object + ubus call network add_dynamic "$(json_dump)" + elif + [ "$v6cap" = 1 -a "$nat46" = 1 ]; then + log "Adding 464XLAT (CLAT) dynamic interface" + json_init + json_add_string name "CLAT$INTER" + json_add_string proto "464xlat" + json_add_string tunlink "${interface}" + [ -n "$zone" ] && json_add_string zone "$zone" + proto_add_dynamic_defaults + json_close_object + ubus call network add_dynamic "$(json_dump)" + fi + fi + + tid=$((tid + 1)) + uci_set_state network $interface tid "$tid" +# SIGNAL=$(umbim $DBG -n -t $tid -d $device signal) +# CSQ=$(echo "$SIGNAL" | awk '/rssi:/ {print $2}') + + $ROOTER/log/logger "Modem #$CURRMODEM Connected" + log "Modem $CURRMODEM Connected" + + IDP=$(uci get modem.modem$CURRMODEM.idP) + IDV=$(uci get modem.modem$CURRMODEM.idV) + + if [ ! -s /tmp/msimdata$CURRMODEM ]; then + echo $IDV" : "$IDP > /tmp/msimdatax$CURRMODEM + echo "$IMEI" >> /tmp/msimdatax$CURRMODEM + echo "$IMSI" >> /tmp/msimdatax$CURRMODEM + echo "$ICCID" >> /tmp/msimdatax$CURRMODEM + echo "1" >> /tmp/msimdatax$CURRMODEM + mv -f /tmp/msimdatax$CURRMODEM /tmp/msimdata$CURRMODEM + fi + + if [ ! -s /tmp/msimnum$CURRMODEM ]; then + echo "$CNUM" > /tmp/msimnumx$CURRMODEM + echo "$CNUMx" >> /tmp/msimnumx$CURRMODEM + mv -f /tmp/msimnumx$CURRMODEM /tmp/msimnum$CURRMODEM + fi + + uci set modem.modem$CURRMODEM.custom=$CUSTOM + uci set modem.modem$CURRMODEM.provider=$PROV + uci set modem.modem$CURRMODEM.down=$DOWN" kbps Down | " + uci set modem.modem$CURRMODEM.up=$UP" kbps Up" + uci set modem.modem$CURRMODEM.mcc=$MCC + uci set modem.modem$CURRMODEM.mnc=" "$MNC + uci set modem.modem$CURRMODEM.sig="--" + uci set modem.modem$CURRMODEM.sms=0 + uci commit modem + + COMMPORT=$(uci get modem.modem$CURRMODEM.commport) + if [ -z $COMMPORT ]; then + ln -s $ROOTER/mbim/mbimdata.sh $ROOTER_LINK/getsignal$CURRMODEM + else + $ROOTER/sms/check_sms.sh $CURRMODEM & + ln -s $ROOTER/signal/modemsignal.sh $ROOTER_LINK/getsignal$CURRMODEM + # send custom AT startup command + if [ $(uci -q get modem.modeminfo$CURRMODEM.at) -eq "1" ]; then + ATCMDD=$(uci -q get modem.modeminfo$CURRMODEM.atc) + if [ ! -z "${ATCMDD}" ]; then + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$($ROOTER/common/processat.sh "$OX") + ERROR="ERROR" + if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` + then + log "Error sending custom AT command: $ATCMDD with result: $OX" + else + log "Sent custom AT command: $ATCMDD with result: $OX" + fi + fi + fi + fi + ln -s $ROOTER/connect/reconnect.sh $ROOTER_LINK/reconnect$CURRMODEM + $ROOTER_LINK/getsignal$CURRMODEM $CURRMODEM $PROT & + ln -s $ROOTER/connect/conmon.sh $ROOTER_LINK/con_monitor$CURRMODEM + $ROOTER_LINK/con_monitor$CURRMODEM $CURRMODEM & + #ln -s $ROOTER/mbim/monitor.sh $ROOTER_LINK/mbim_monitor$CURRMODEM + #$ROOTER_LINK/mbim_monitor$CURRMODEM $CURRMODEM $device & + + uci set modem.modem$CURRMODEM.connected=1 + uci commit modem + + if [ -e $ROOTER/connect/postconnect.sh ]; then + $ROOTER/connect/postconnect.sh $CURRMODEM + fi + + if [ -e $ROOTER/timezone.sh ]; then + TZ=$(uci -q get modem.modeminfo$CURRMODEM.tzone) + if [ "$TZ" = "1" ]; then + $ROOTER/timezone.sh & + fi + fi + CLB=$(uci -q get modem.modeminfo$CURRMODEM.lb) + if [ -e /etc/config/mwan3 ]; then + INTER=$(uci get modem.modeminfo$CURRMODEM.inter) + if [ -z $INTER ]; then + INTER=0 + else + if [ $INTER = 0 ]; then + INTER=$CURRMODEM + fi + fi + ENB=$(uci -q get mwan3.wan$CURRMODEM.enabled) + if [ ! -z $ENB ]; then + if [ $CLB = "1" ]; then + uci set mwan3.wan$INTER.enabled=1 + else + uci set mwan3.wan$INTER.enabled=0 + fi + uci commit mwan3 + /usr/sbin/mwan3 restart + fi + fi + rm -f /tmp/usbwait + + return 0 +} + +proto_mbim_setup() { + + local ret + _proto_mbim_setup $@ + ret=$? + + [ "$ret" = 0 ] || { + log "MBIM bringup failed, retry in 5s" + CPORT=$(uci get modem.modem$CURRMODEM.commport) + ATCMDD="AT+COPS=0" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + sleep 5 + } + + exit 0 + return $ret +} + +proto_mbim_teardown() { + local interface="$1" + + local device + json_get_vars device + local tid=$(uci_get_state network $interface tid) + + [ -n "$ctl_device" ] && device=$ctl_device + + if [ -n "$device" ]; then + log "Stopping network" + if [ -n "$tid" ]; then + tid=$((tid + 1)) + umbim $DBG -t $tid -d "$device" disconnect + uci_revert_state network $interface tid + else + umbim $DBG -d "$device" disconnect + fi + fi + + proto_init_update "*" 0 + proto_send_update "$interface" + +} + +[ -n "$INCLUDE_ONLY" ] || add_protocol mbim diff --git a/rooter/0drivers/rmbim/files/usr/lib/rooter/mbim/mbimdata.sh b/rooter/0drivers/rmbim/files/usr/lib/rooter/mbim/mbimdata.sh new file mode 100644 index 0000000..41f6f10 --- /dev/null +++ b/rooter/0drivers/rmbim/files/usr/lib/rooter/mbim/mbimdata.sh @@ -0,0 +1,115 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK=$ROOTER"/links" + +log() { + logger -t "MBIM Data" "$@" +} + +STARTIMEX=$(date +%s) +MONSTAT= +rm -f /tmp/monstat$CURRMODEM + +build_status() { + CSQ=$signal + if [ $CSQ -ge 0 -a $CSQ -le 31 ]; then + CSQ_PER=$(($CSQ * 100/31)) + CSQ_RSSI=$((2 * CSQ - 113)) + CSQX=$CSQ_RSSI + [ $CSQ -eq 0 ] && CSQ_RSSI="<= "$CSQ_RSSI + [ $CSQ -eq 31 ] && CSQ_RSSI=">= "$CSQ_RSSI + CSQ_PER=$CSQ_PER"%" + CSQ_RSSI=$CSQ_RSSI" dBm" + else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" + fi + echo "-" > /tmp/status$CURRMODEM.file + echo "$CSQ" >> /tmp/status$CURRMODEM.file + echo "$CSQ_PER" >> /tmp/status$CURRMODEM.file + echo "$CSQ_RSSI" >> /tmp/status$CURRMODEM.file + echo "$manuf" >> /tmp/status$CURRMODEM.file + echo "$provider" >> /tmp/status$CURRMODEM.file + echo "$cellmode" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$mcc" >> /tmp/status$CURRMODEM.file + echo "$mnc" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$down" >> /tmp/status$CURRMODEM.file + echo "$up" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo " " >> /tmp/status$CURRMODEM.file + echo " " >> /tmp/status$CURRMODEM.file + echo "$MONSTAT" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$conn" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "MBIM" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file +} + +CURRMODEM=$1 + +conn="Modem #"$CURRMODEM +custom=$(uci get modem.modem$CURRMODEM.custom) +port=$(uci get modem.modem$CURRMODEM.wdm) +netd=$(uci get modem.modem$CURRMODEM.wwan) +manuf=$(uci get modem.modem$CURRMODEM.manuf) +model=$(uci get modem.modem$CURRMODEM.model) +mcc=$(uci get modem.modem$CURRMODEM.mcc) +mnc=$(uci get modem.modem$CURRMODEM.mnc) +up=$(uci get modem.modem$CURRMODEM.up) +down=$(uci get modem.modem$CURRMODEM.down) +provider=$(uci get modem.modem$CURRMODEM.provider) +cellmode=$(uci get modem.modem$CURRMODEM.mode) +if [ $cellmode = "CUSTOM" ]; then + cellmode=$custom +fi +signal=$(uci get modem.modem$CURRMODEM.sig) + +device="/dev/cdc-wdm"$port +netdev="wwan"$netd +manuf=$manuf" "$model + +tid=2 +while [ 1 -eq 1 ]; do + tid=2 + #SIGNAL=$(umbim -n -t $tid -d $device signal) + tid=$((tid + 1)) + #SIGNAL=$(umbim -n -t $tid -d $device signal) + signal=0 + if [ -e /tmp/monstat$CURRMODEM ]; then + source /tmp/monstat$CURRMODEM + fi + if [ -z $MONSTAT ]; then + MONSTAT="Unknown" + fi + build_status + if [ -e /etc/netspeed ]; then + NETSPEED=60 + else + NETSPEED=10 + fi + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEX + while [ $ELAPSE -lt $NETSPEED ]; do + sleep 2 + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEX + done + STARTIMEX=$CURRTIME +done diff --git a/rooter/0drivers/rmbim/files/usr/lib/rooter/mbim/monitor.sh b/rooter/0drivers/rmbim/files/usr/lib/rooter/mbim/monitor.sh new file mode 100644 index 0000000..0e84aec --- /dev/null +++ b/rooter/0drivers/rmbim/files/usr/lib/rooter/mbim/monitor.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +. /lib/functions.sh + +ROOTER_LINK="/tmp/links" + +log() { + logger -t "MBIM Monitor" "$@" +} + +CURRMODEM=$1 +DEVICE=$2 + +while :; do + tid=$(uci_get_state network wan$CURRMODEM tid) + tid=$((tid + 1)) + umbim -d $DEVICE -n -t $tid status >/dev/null + retq=$? + uci_toggle_state network wan$CURRMODEM tid $tid + [ $retq -ne 0 ] && break + sleep 10 +done + +case $retq in +2) + error="activation state: activating" + ;; +3) + error="activation state: deactivated" + ;; +4) + error="activation state: deactivating" + ;; +255) + error="MBIM message not long enough" + ;; +esac + +log "Modem $CURRMODEM Connection is Down ($error)" +if [ -f $ROOTER_LINK/reconnect$CURRMODEM ]; then + $ROOTER_LINK/reconnect$CURRMODEM $CURRMODEM & +fi + +# wait to be killed by mbim.sh +sleep 60 diff --git a/rooter/0drivers/rqmi/Makefile b/rooter/0drivers/rqmi/Makefile new file mode 100644 index 0000000..0674e1f --- /dev/null +++ b/rooter/0drivers/rqmi/Makefile @@ -0,0 +1,52 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=uqmi +PKG_RELEASE:=$(AUTORELEASE) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL=$(PROJECT_GIT)/project/uqmi.git +PKG_SOURCE_DATE:=2022-05-04 +PKG_SOURCE_VERSION:=56cb2d4056fef132ccf78dfb6f3074ae5d109992 +PKG_MIRROR_HASH:=cc832b5318805df8c8387a3650f250dee72d5f1dbda4e4866b5503e186b2210c +PKG_MAINTAINER:=Matti Laakso + +PKG_LICENSE:=GPL-2.0 +PKG_LICENSE_FILES:= + +PKG_FLAGS:=nonshared + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +define Package/rqmi + SECTION:=net + CATEGORY:=ROOter + SUBMENU:=Drivers + DEPENDS:=+libubox +libblobmsg-json +kmod-usb-net +kmod-usb-net-qmi-wwan +wwan + TITLE:=Control utility for mobile broadband modems +endef + +define Package/rqmi/description + uqmi is a command line tool for controlling mobile broadband modems using + the QMI-protocol. +endef + +TARGET_CFLAGS += \ + -I$(STAGING_DIR)/usr/include \ + -ffunction-sections \ + -fdata-sections \ + -Wno-error=dangling-pointer \ + -Wno-error=maybe-uninitialized + +TARGET_LDFLAGS += -Wl,--gc-sections + +CMAKE_OPTIONS += \ + -DDEBUG=1 + +define Package/rqmi/install + $(INSTALL_DIR) $(1)/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/uqmi $(1)/sbin/ + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,rqmi)) diff --git a/rooter/0drivers/rqmi/files/usr/lib/rooter/qmi/connectqmi.sh b/rooter/0drivers/rqmi/files/usr/lib/rooter/qmi/connectqmi.sh new file mode 100644 index 0000000..7dc6d02 --- /dev/null +++ b/rooter/0drivers/rqmi/files/usr/lib/rooter/qmi/connectqmi.sh @@ -0,0 +1,293 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + modlog "QMI Connect $CURRMODEM" "$@" +} + + . /lib/functions.sh + . /lib/netifd/netifd-proto.sh + +CURRMODEM=$1 +devname=$2 +device=/dev/$2 +auth=$3 +NAPN=$4 +username=$5 +password=$6 +RAW=$7 +DHCP=$8 +pincode=$9 + +enb=$(uci -q get custom.connect.ipv6) +if [ -z $enb ]; then + enb="1" +fi + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + +INTER=$(uci -q get modem.modem$CURRMODEM.inter) +interface="wan"$INTER + +case $auth in + "0" ) + auth="none" + ;; + "1" ) + auth="pap" + ;; + "2" ) + auth="chap" + ;; + *) + auth="none" + ;; +esac + +if [ $username = NIL ]; then + username= +fi +if [ $password = NIL ]; then + password= +fi + +ifname="$(ls /sys/class/usbmisc/$devname/device/net/)" + +#while uqmi -s -d "$device" --get-pin-status | grep '"UIM uninitialized"' > /dev/null; do +# sleep 1; +#done + +[ -n "$pincode" ] && { + uqmi -s -d "$device" --verify-pin1 "$pincode" || { + log "Unable to verify PIN" + ret=1 + } +} + +uqmi -s -d "$device" --stop-network 0xffffffff --autoconnect > /dev/null & sleep 5 ; kill -9 $! +uqmi -s -d "$device" --set-device-operating-mode online > /dev/null 2>&1 & sleep 5 ; kill -9 $! + +if [ $RAW -eq 1 ]; then + DATAFORM='"raw-ip"' +else + if [ $idV = 1199 -a $idP = 9055 ]; then + $ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "reset.gcom" "$CURRMODEM" + DATAFORM='"802.3"' + uqmi -s -d "$device" --set-data-format 802.3 + uqmi -s -d "$device" --wda-set-data-format 802.3 + else + log "getting data format" + DATAFORM=$(uqmi -s -d "$device" --wda-get-data-format) + fi +fi + +log "WDA-GET-DATA-FORMAT is $DATAFORM" +if [ "$DATAFORM" = '"raw-ip"' ]; then + [ -f /sys/class/net/$ifname/qmi/raw_ip ] || { + log "Device only supports raw-ip mode but is missing this required driver attribute: /sys/class/net/$ifname/qmi/raw_ip" + ret=1 + } + echo "Y" > /sys/class/net/$ifname/qmi/raw_ip +fi + +log "Query radio state" +uqmi -s -d "$device" --get-signal-info | grep -q "Information unavailable" & sleep 5 ; kill -9 $! +STATUS=$? + +[ "$STATUS" -ne 0 ] || { + sleep 1 + log "Setting FCC Auth" + uqmi -s -d "$device" --fcc-auth & sleep 5 ; kill -9 $! + sleep 1 + } + +uqmi -s -d "$device" --sync > /dev/null 2>&1 & sleep 5 ; kill -9 $! + +#uqmi -s -d "$device" --network-register > /dev/null 2>&1 + +log "Waiting for network registration" +td=0 +while uqmi -s -d "$device" --get-serving-system | grep '"searching"' > /dev/null; do + sleep 5; + tid=$((tid + 1)) + if [ $tid -gt 2 ]; then + uqmi -s -d "$device" --stop-network 0xffffffff --autoconnect > /dev/null & sleep 10 ; kill -9 $! + exit 1 + fi +done + +cid=`uqmi -s -d "$device" --get-client-id wds` +[ $? -ne 0 ] && { + log "Unable to obtain client ID" + ret=1 +} + +uqmi -s -d "$device" --set-client-id wds,"$cid" --set-ip-family ipv4 > /dev/null + +isplist=$(uci -q get modem.modeminfo$CURRMODEM.isplist) +apn2=$(uci -q get modem.modeminfo$CURRMODEM.apn2) +for isp in $isplist + do + NAPN=$(echo $isp | cut -d, -f2) + NPASS=$(echo $isp | cut -d, -f4) + CID=$(echo $isp | cut -d, -f5) + NUSER=$(echo $isp | cut -d, -f6) + NAUTH=$(echo $isp | cut -d, -f7) + if [ "$NPASS" = "nil" ]; then + NPASS="NIL" + fi + if [ "$NUSER" = "nil" ]; then + NUSER="NIL" + fi + if [ "$NAUTH" = "nil" ]; then + NAUTH="0" + fi + username="$NUSER" + password="$NPASS" + auth=$NAUTH + case $auth in + "0" ) + auth="none" + ;; + "1" ) + auth="pap" + ;; + "2" ) + auth="chap" + ;; + "*" ) + auth="none" + ;; + esac + + if [ ! -e /etc/config/isp ]; then + log "Connect to network using $NAPN" + else + log "Connect to network" + fi + + if [ ! -e /etc/config/isp ]; then + log "$NAPN $auth $username $password" + fi + + conn=0 + tidd=0 + tcnt=4 + while true; do + ST=$(uqmi -s -d "$device" --set-client-id wds,"$cid" --start-network ${NAPN:+--apn $NAPN} ${auth:+--auth-type $auth} \ + ${username:+--username $username} ${password:+--password $password}) + log "Connection returned : $ST" + CONN=$(uqmi -s -d "$device" --get-data-status) + log "Status is $CONN" + if [[ $(echo "$CONN" | grep -o "disconnected") ]]; then + sleep 1 + tidd=$((tidd + 1)) + if [ $tidd -gt $tcnt ]; then + break + fi + else + conn=1 + break + fi + done + if [ $conn -eq 1 ]; then + break; + fi + done + +if [[ -z $(echo "$CONN" | grep -o "disconnected") ]]; then + ret=0 + + CONN4=$(uqmi -s -d "$device" --set-client-id wds,"$cid" --get-current-settings) + log "GET-CURRENT-SETTINGS is $CONN4" + + if [ $enb = "1" ]; then + cid6=`uqmi -s -d "$device" --get-client-id wds` + [ $? -ne 0 ] && { + log "Unable to obtain client ID" + ret=1 + } + + uqmi -s -d "$device" --set-client-id wds,"$cid6" --set-ip-family ipv6 > /dev/null + ST6=$(uqmi -s -d "$device" --set-client-id wds,"$cid6" --start-network ${NAPN:+--apn $NAPN} ${auth:+--auth-type $auth} \ + ${username:+--username $username} ${password:+--password $password}) + log "IPv6 Connection returned : $ST6" + CONN6=$(uqmi -s -d "$device" --set-client-id wds,"$cid6" --get-current-settings) + CONF6=$(jsonfilter -s $CONN6 -e '@.ipv6') + if [ -n "$CONF6" ];then + log "IPv6 settings are $CONF6" + touch /tmp/ipv6supp$INTER + else + rm -f /tmp/ipv6supp$INTER + fi + fi + + if [ $DATAFORM = '"raw-ip"' ]; then + log "Handle raw-ip" + json_load "$CONN4" + json_select ipv4 + json_get_vars ip subnet gateway dns1 dns2 + if [ $enb = "1" ]; then + if [ -n "$CONF6" ]; then + json_load "$CONN6" + json_select ipv6 + json_get_var ip_6 ip + json_get_var gateway_6 gateway + json_get_var dns1_6 dns1 + json_get_var dns2_6 dns2 + json_get_var ip_prefix_length ip-prefix-length + fi + fi + + if [ -s /tmp/v4dns$INTER -o -s /tmp/v6dns$INTER ]; then + pdns=1 + if [ -s /tmp/v4dns$INTER ]; then + v4dns=$(cat /tmp/v4dns$INTER 2>/dev/null) + fi + if [ $enb = "1" ]; then + if [ -s /tmp/v6dns$INTER ]; then + v6dns=$(cat /tmp/v6dns$INTER 2>/dev/null) + fi + fi + else + v4dns="$dns1 $dns2" + if [ $enb = "1" ]; then + v6dns="$dns1_6 $dns2_6" + echo "$v6dns" > /tmp/v6dns$INTER + fi + fi + + if [ $DHCP -eq 0 ]; then + log Applying IP settings to wan$INTER + uci delete network.wan$INTER + uci set network.wan$INTER=interface + uci set network.wan$INTER.proto=static + uci set network.wan$INTER.${ifname1}=$ifname + uci set network.wan$INTER.metric=$INTER"0" + uci set network.wan$INTER.ipaddr=$ip/$subnet + uci set network.wan$INTER.gateway='0.0.0.0' + uci set network.wan$INTER.dns="$v4dns" + uci commit network + uci set modem.modem$CURRMODEM.interface=$ifname + uci commit modem + else + proto_init_update "$ifname" 1 + proto_set_keep 1 + proto_add_ipv4_address "$ip" "$subnet" + proto_add_ipv4_route "0.0.0.0" 0 + for DNSV in $(echo "$v4dns"); do + proto_add_dns_server "$DNSV" + done + proto_send_update "$interface" + fi + fi +else + uqmi -s -d "$device" --stop-network 0xffffffff --autoconnect > /dev/null & sleep 10 ; kill -9 $! + ret=1 +fi + +exit $ret diff --git a/rooter/0mesh/mesh-mesh/Makefile b/rooter/0mesh/mesh-mesh/Makefile new file mode 100644 index 0000000..39281b6 --- /dev/null +++ b/rooter/0mesh/mesh-mesh/Makefile @@ -0,0 +1,34 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=mesh-mesh +PKG_VERSION:=4.500 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/mesh-mesh + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Mesh Support + DEPENDS:=+kmod-batman-adv +alfred +batctl +ip + TITLE:=Install scripts for Mesh Network + PKGARCH:=all +endef + +define Package/mesh-mesh/description + Install scripts for Mesh Network +endef + + +define Build/Compile +endef + +define Package/mesh-mesh/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,mesh-mesh)) diff --git a/rooter/0mesh/mesh-mesh/files/etc/config/batman-adv b/rooter/0mesh/mesh-mesh/files/etc/config/batman-adv new file mode 100644 index 0000000..0b4e014 --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/etc/config/batman-adv @@ -0,0 +1,16 @@ +config mesh 'bat0' + option aggregated_ogms '1' + option ap_isolation '0' + option bonding '0' + option fragmentation '0' + option gw_bandwidth '10000/2000' + option gw_mode 'client' + option gw_sel_class '20' + option log_level '2' + option orig_interval '1000' + option bridge_loop_avoidance '1' + option distributed_arp_table '1' + option multicast_mode '1' + option network_coding '0' + option hop_penalty '30' + option isolation_mark '0' \ No newline at end of file diff --git a/rooter/0mesh/mesh-mesh/files/etc/config/mesh b/rooter/0mesh/mesh-mesh/files/etc/config/mesh new file mode 100644 index 0000000..959ba5a --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/etc/config/mesh @@ -0,0 +1,18 @@ + +config radio 'radio' + option radionumber '0' + option usedfs '1' + option channelwidth '0' + option channellist '0' + option channelindex '10' + option dedicated '0' + +config network 'network' + option networkid 'MeshCloud' + option netencrypted '1' + option netpassword 'MeshPassword123' + +config roam 'roam' + option signalenable '1' + option signalid 'abcd' + diff --git a/rooter/0mesh/mesh-mesh/files/etc/hotplug.d/net/99-batman-gw b/rooter/0mesh/mesh-mesh/files/etc/hotplug.d/net/99-batman-gw new file mode 100644 index 0000000..600f70b --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/etc/hotplug.d/net/99-batman-gw @@ -0,0 +1,34 @@ +#!/bin/sh + +dhcp4_discover () { + ifup lan_dhcp +} + +dhcp4_kill () { + ifdown lan_dhcp +} + +dnsmasq_start () { + uci revert -P/var/state dhcp.@dnsmasq[0].domainneeded + uci revert -P/var/state dhcp.@dnsmasq[0].boguspriv + uci revert -P/var/state dhcp.@dnsmasq[0].rebind_protection + uci revert -P/var/state dhcp.lan.ignore + /etc/init.d/dnsmasq restart +} + +dnsmasq_stop () { + uci set -P/var/state dhcp.@dnsmasq[0].domainneeded= + uci set -P/var/state dhcp.@dnsmasq[0].boguspriv= + uci set -P/var/state dhcp.@dnsmasq[0].rebind_protection=0 + uci set -P/var/state dhcp.lan.ignore=1 + echo no-dhcp-interface=br-lan >> /var/etc/dnsmasq.conf + /etc/init.d/dnsmasq restart +} + +if [ "$BATTYPE" = "gw" ] ; then + case "$BATACTION" in + add) dnsmasq_stop ; dhcp4_discover ;; + del) dhcp4_kill ; dnsmasq_start ;; + change) dhcp4_kill ; sleep 5 ; dhcp4_discover ;; + esac +fi diff --git a/rooter/0mesh/mesh-mesh/files/etc/init.d/zmesh b/rooter/0mesh/mesh-mesh/files/etc/init.d/zmesh new file mode 100644 index 0000000..68e6158 --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/etc/init.d/zmesh @@ -0,0 +1,9 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +START=99 + +start() { + /usr/lib/mesh/checker.sh +} + diff --git a/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/controller/batman.lua b/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/controller/batman.lua new file mode 100644 index 0000000..8f2cf83 --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/controller/batman.lua @@ -0,0 +1,249 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2012 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.batman", package.seeall) + +local function split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + return t +end + + +function index() + local page + + page = node("admin", "mesh", "batman") + page.target = template("batman/batman") + page.title = _("Mesh Status") + page.order = 1 + + node("batman") + + page = node("batman", "json") + page.target = call("act_json") + + page = node("batman", "topo") + page.target = call("act_topo") + page.leaf = true + + page = node("batman", "graph") + page.target = template("batman_graph") + page.leaf = true +end + +function act_topo(mode) + if not mode or mode == "dot" or mode == "json" then + local fd = io.popen("batadv-vis -f %s" %( mode or "dot" )) + if fd then + if mode == "json" then + luci.http.prepare_content("application/json") + luci.http.write("[") + local ln + repeat + ln = fd:read("*l") + if ln then + luci.http.write(ln) + luci.http.write(", ") + end + until not ln + luci.http.write("{ } ]") + else + luci.http.prepare_content("text/vnd.graphviz") + luci.http.header("Content-Disposition", + "attachment; filename=topo-%s-%s.vd" + %{ luci.sys.hostname(), os.date("%Y%m%d-%H%M%S") }) + luci.http.write(fd:read("*a")) + end + fd:close() + else + luci.http.status(500, "No data") + end + else + luci.http.status(500, "Bad mode") + end +end + +function act_json() + local v, l, fd + local rv = { + interfaces = { }, + originators = { }, + gateways = { } + } + + -- + -- interfaces + -- + fd = io.popen("batctl if") + if fd then + repeat + l = fd:read("*l") + v = l and l:match("^(.-):") + if v then + rv.interfaces[#rv.interfaces+1] = v + end + until not l + fd:close() + end + +os.execute("cat /proc/net/arp > /tmp/arp") + +iplist = {} +maclist = {} +index = 0 +fd = io.open("/tmp/arp") +if fd then + -- skip header line + fd:read("*l") + repeat + l = fd:read("*l") + if l then + lan = l + s1, e1 = lan:find("0x2") + if s1 ~= nil then + s, e = l:find(" ") + if s ~= nil then + ip = l:sub(0, e-1) + + fc = io.popen("batctl translate " .. ip) + if fc then + mac = fc:read("*l") + fc:close() + iplist[index] = ip + maclist[index] = mac + index = index + 1 + end + end + end + end + until not l + fd:close() +end + + -- + -- originators + -- + local originators_command = ( + "batctl o -H 2>/dev/null ".. -- gets originators from batctl + "| tr -d '[]()' ".. -- removes brackets and parenthesis + "| sed 's/^ / -/g' ".. -- normalizes output, adding a minus when no asterisk is outputed in each line + "| sed 's/^ //g' ".. -- removes the space from the beginning of the line + "| sed -r 's/\\s+/,/g'".. -- replaces tabs for commas + "| sed -r 's/s,/,/g'" -- removes the 's' from the last_seen field referencing seconds + ) + fd = io.popen(originators_command) + if fd then + repeat + l = fd:read() + if l then + local asterisk, originator_name, last_seen, link_quality, next_hop, outgoing_if + asterisk, originator_name, last_seen, link_quality, next_hop, outgoing_if = unpack(split(l, ",")) + if originator_name and last_seen and link_quality then + if originator_name == next_hop then + next_hop = "Here" + end + if index > 0 then + for j=0,index-1 do + if maclist[j] == originator_name then + originator_name = iplist[j] .. " (" .. originator_name .. ")" + end + if maclist[j] == next_hop then + next_hop = iplist[j] + end + end + end + rv.originators[#rv.originators+1] = { + originator_name, + tonumber(last_seen) * 1000, + tonumber(link_quality), + next_hop, + outgoing_if + } + end + end + until not l + fd:close() + end + + -- + -- gateways + -- + fd = io.popen("batctl gwl") + if fd then + -- skip header line + fd:read("*l") + fd:read("*l") + + repeat + l = fd:read("*l") + if l then + local a, m, q, n, i, r = l:match("^(%S*) +([^ ]+) +%( *(%d+)%) +([^ ]+) +%[ *(%S+)%]: +(%S+)") + if a and m and q and n and i and r then + c="0" + if index > 0 then + for j=0,index-1 do + if maclist[j] == m then + m = iplist[j] + end + if maclist[j] == n then + n = iplist[j] + end + end + end + rv.gateways[#rv.gateways+1] = { + #a > 0, + m, + tonumber(q), + n, + i, + tonumber(c), + r + } + end + end + until not l + fd:close() + end + + -- local Gateway status + + rv.status = "Client" + fd = io.popen("batctl gw") + if fd then + l = fd:read("*l") + s, e = l:find("server") + if s ~= nil then + rv.status = "Server" + end + fd:close() + end + + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end diff --git a/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/controller/mesh.lua b/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/controller/mesh.lua new file mode 100644 index 0000000..923cec2 --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/controller/mesh.lua @@ -0,0 +1,76 @@ +module("luci.controller.mesh", package.seeall) +function index() + local page + entry({"admin", "mesh"}, firstchild(), "Mesh", 71).dependent=false + page = entry({"admin", "mesh", "mesh"}, template("mesh/mesh-setup"), "Mesh Configuration", 71) + page.dependent = true + + entry({"admin", "mesh", "getstate"}, call("action_getstate")) + entry({"admin", "mesh", "sendmeshstate"}, call("action_sendmeshstate")) + entry({"admin", "mesh", "meshcfg"}, call("action_meshcfg")) + entry({"admin", "mesh", "meshstartstop"}, call("action_meshstartstop")) +end + +function action_getstate() + local rv = {} + local radiolist = {} + + file = io.open("/etc/meshrun", "r") + if file == nil then + rv["state"] = "0" + else + rv["state"] = "1" + file:close() + end + os.execute("/usr/lib/mesh/radio.sh ") + file = io.open("/tmp/radiolist", "r") + if file ~= nil then + j = file:read("*line") + rv['radio'] = j + if j ~=0 then + for i=0, j-1 do + radiolist[i] = file:read("*line") + end + rv['radiolist'] = radiolist + end + rv['radionumber'] = file:read("*line") + rv['channelindex'] = file:read("*line") + rv['channellist'] = file:read("*line") + rv['channelwidth'] = file:read("*line") + rv['usedfs'] = file:read("*line") + rv['dedicated'] = file:read("*line") + + rv['networkid'] = file:read("*line") + rv['netencrypted'] = file:read("*line") + rv['netpassword'] = file:read("*line") + + rv['signalenable'] = file:read("*line") + rv['signalid'] = file:read("*line") + + file:close() + else + rv["radio"] = "0" + end + + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_sendmeshstate() + local set = luci.http.formvalue("set") + + os.execute('/usr/lib/mesh/save.sh "' .. set .. '"') +end + +function action_meshcfg() + local set = luci.http.formvalue("set") + + os.execute('/usr/lib/mesh/savecfg.sh "' .. set .. '"') +end + +function action_meshstartstop() + os.execute('/usr/lib/mesh/startstop.sh') + os.execute("reboot &") +end + diff --git a/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/view/batman/batman.htm b/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/view/batman/batman.htm new file mode 100644 index 0000000..d23421c --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/view/batman/batman.htm @@ -0,0 +1,300 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2012 Jo-Philipp Wich + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ + +-%> + +<% luci.http.prepare_content("text/html") %> + +<%+header%> + + + + + + + + +

              <%:Mesh Status%>

              + +
              + + + + + + +
              Internet Status :
                +
                + +
                + <%:Active Mesh Nodes%> + + + + + + + + + + + +
                <%:Link Quality%><%:MAC-Address%><%:Last Seen%><%:Interface%><%:Next Hop%>

                <%:Collecting data...%>
                +
                + +
                + <%:Other Mesh Nodes with Internet Access%> + + + + + + + + + + + +
                <%:MAC-Address%><%:Speed%><%:Link Quality%><%:Interface%><%:Next Hop%>

                <%:Collecting data...%>
                +
                + +
                + <%:Visualization%> +
                +
                + +<%+footer%> diff --git a/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/view/mesh/mesh-setup.htm b/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/view/mesh/mesh-setup.htm new file mode 100644 index 0000000..60a652b --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/usr/lib/lua/luci/view/mesh/mesh-setup.htm @@ -0,0 +1,912 @@ +<%+header%> +<% +local sys = require "luci.sys" +local utl = require "luci.util" +local fs = require "nixio.fs" + +function showicon(lck) + if lck == 0 then + return resource .. "/icons/unlock1.png" + else + return resource .. "/icons/lock1.png" + end +end + +-%> + + + +
                +
                +

                Mesh Network Configuration

                +
                + +
                + + + + + + + + + + + + + + + + + + + + + +
                Config Status
                Import Configuration File
                Export Configuration File
                Save Settings
                Apply Settings
                Reload Settings
                No Changes
                + + + +
                + + + +
                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                Mesh Radio Settings
                Select Backhaul Radio
                + +
                Dedicated Backhaul Radio
                Select Backhaul Channel
                + +
                Select Backhaul Channel
                + +
                Use DFS Channels
                Select Backhaul Channel
                + +
                Use DFS Channels
                Channel Bandwidth
                + +
                Channel Bandwidth
                + +
                Channel Bandwidth
                + +
                Channel Bandwidth
                + +
                + +
                + +
                + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                Mesh Network Settings
                Mesh Network ID
                Network Encrypted
                +
                + +
                + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                Access Point Roaming
                Enable Low Signal Roaming
                Roaming ID
                + + + + + +
                + +
                + +
                + +
                +
                +<%+footer%> \ No newline at end of file diff --git a/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/checker.sh b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/checker.sh new file mode 100644 index 0000000..9bf3cbf --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/checker.sh @@ -0,0 +1,251 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Checker" "$@" +} + +channel2="1,2,3,4,5,6,7,8,9,10,11,12,13,14" +channel5="36,40,44,48,149,153,157,161,165,169" +channel5dfs="36,40,44,48,52,56,60,64,100,104,104,112,116,132,136,140,144,149,153,157,161,165,169" + +absolute() { + num=$1 + if [ "$num" -lt 0 ]; then + num=$((-num)) + fi +} + +loadconfig() { + X=$(uci -q get wireless.wmesh.device) + uci set mesh.radio.radionumber=$(echo ${X#radio}) + + uci set mesh.radio.dedicated=$(uci -q get wireless.default_$X.disabled) + + chanwidth=$(uci -q get wireless.$X.htmode) + case $chanwidth in + "HT20" ) + chanwidth=0 + ;; + "HT40" ) + chanwidth=1 + ;; + "VHT80" ) + chanwidth=2 + ;; + "VHT160" ) + chanwidth=2 + ;; + esac + uci set mesh.radio.channelwidth=$chanwidth + + chan=$(uci -q get wireless.$X.channel) + if [ $chan -lt 15 ]; then + uci set mesh.radio.channellist=0 + uci set mesh.radio.channelindex=$((${chan}-1)) + else + dfs=$(uci -q get wireless.$X.usedfs) + if [ -z $dfs ]; then + dfs=1 + uci set mesh.radio.usedfs=1 + else + uci set mesh.radio.usedfs=$dfs + fi + if [ $dfs -eq 0 ]; then + uci set mesh.radio.channellist=1 + clist=$channel5 + else + uci set mesh.radio.channellist=2 + clist=$channel5dfs + fi + cindex=1 + while [ true ] + do + chan=$(echo "$clist" | cut -d, -f$cindex) + if [ $chan -eq $channel ]; then + uci set mesh.radio.channelindex=$((${cindex}-1)) + break + fi + cindex=$((${cindex}+1)) + done + fi + + enc=$(uci -q get wireless.wmesh.encryption) + if [ $enc = "sae" ]; then + uci set mesh.network.netencrypted=1 + uci set mesh.network.netpassword=$(uci -q get wireless.wmesh.key) + else + uci set mesh.network.netencrypted=0 + uci set mesh.network.netpassword="password" + fi + + uci set mesh.network.networkid=$(uci -q get wireless.wmesh.mesh_id) + + snr=$(uci -q get wireless.default_$X.ieee80211r) + if [ ! -z $snr ]; then + uci set mesh.roam.signalenable=$snr + uci set mesh.roam.signalid=$(uci -q get wireless.default_$X.mobility_domain) + else + uci set mesh.roam.signalenable=0 + uci set mesh.roam.signalid="abcd" + fi + + uci commit mesh +} + +count_radio() { + local config=$1 + local channel + + uci set wireless.default_radio$count.ieee80211r=$signalenable + uci set wireless.default_radio$count.mobility_domain=$signalid + uci set wireless.default_radio$count.ft_over_ds="1" + uci set wireless.default_radio$count.ft_psk_generate_local="1" + count=$((${count}+1)) + +} + +loadmesh() { + radionum=$(uci -q get mesh.radio.radionumber) + dedicated=$(uci -q get mesh.radio.dedicated) + if [ -z $dedicated ]; then + dedicated="0" + fi + log "default_radio$radionum disabled = $dedicated" + + chanwidth=$(uci -q get mesh.radio.channelwidth) + case $chanwidth in + "0" ) + chanwidth=20 + ;; + "1" ) + chanwidth=40 + ;; + "2" ) + chanwidth=80 + ;; + "3" ) + chanwidth=80 + ;; + esac + cwidth=$(uci -q get wireless.radio$radionum.htmode) + ht=$(echo "$cwidth" | grep "VHT") + if [ ! -z $ht ]; then + cwidth="VHT"$chanwidth + else + cwidth="HT"$chanwidth + fi + log "radio$radionum htmode = $cwidth" + + clist=$(uci -q get mesh.radio.channellist) + cindex=$(uci -q get mesh.radio.channelindex) + cindex=$((${cindex}+1)) + case $clist in + "0" ) + channel=$(echo "$channel2" | cut -d, -f$cindex) + ;; + "1" ) + channel=$(echo "$channel5" | cut -d, -f$cindex) + ;; + "2" ) + channel=$(echo "$channel5dfs" | cut -d, -f$cindex) + ;; + esac + log "radio$radionum channel = $channel" + + networkid=$(uci -q get mesh.network.networkid) + netencrypted=$(uci -q get mesh.network.netencrypted) + netpassword=$(uci -q get mesh.network.netpassword) + log "mesh_id = $networkid" + log "encryption = $netencrypted key = $netpassword" + + signalenable=$(uci -q get mesh.roam.signalenable) + signalid=$(uci -q get mesh.roam.signalid) + log "roam enable = $signalenable" + log "id = $signalid" + + ipaddr=$(uci -q get network.lan.ipaddr) + + uci set wireless.default_radio$radionum.disabled=$dedicated + uci set wireless.radio$radionum.htmode=$cwidth + uci set wireless.radio$radionum.channel=$channel + + count=0 + config_load wireless + config_foreach count_radio wifi-iface + + uci set wireless.wmesh=wifi-iface + uci set wireless.wmesh.device=radio$radionum + uci set wireless.wmesh.network="mesh" + uci set wireless.wmesh.ifname="if-mesh" + uci set wireless.wmesh.mode="mesh" + uci set wireless.wmesh.mesh_fwding="0" + uci set wireless.wmesh.mesh_id=$networkid + uci set wireless.w.encryption="none" + if [ $netencrypted = "1" ]; then + uci set wireless.wmesh.encryption="sae" + uci set wireless.wmesh.key=$netpassword + fi + uci set wireless.wmesh.mesh_ttl='1' + uci set wireless.wmesh.mcast_rate='24000' + uci set wireless.wmesh.disabled='0' + uci commit wireless + + uci set alfred.alfred.batmanif='bat0' + uci set alfred.alfred.disabled='0' + uci commit alfred + + uci set network.bat0=interface + uci set network.bat0.proto='batadv' + uci set network.bat0.routing_algo='BATMAN_IV' + uci set network.bat0.aggregated_ogms='1' + uci set network.bat0.ap_isolation='0' + uci set network.bat0.bonding='0' + uci set network.bat0.bridge_loop_avoidance='1' + uci set network.bat0.distributed_arp_table='1' + uci set network.bat0.fragmentation='1' + uci set network.bat0.gw_mode='off' + uci set network.bat0.hop_penalty='30' + uci set network.bat0.isolation_mark='0x00000000/0x00000000' + uci set network.bat0.log_level='0' + uci set network.bat0.multicast_mode='1' + uci set network.bat0.multicast_fanout='16' + uci set network.bat0.network_coding='0' + uci set network.bat0.orig_interval='1000' + + uci set network.mesh=interface + uci set network.mesh.proto='batadv_hardif' + uci set network.mesh.master='bat0' + uci set network.mesh.mtu='2304' + uci set network.mesh.throughput_override='0' + + uci set network.bat0_hardif_eth0=interface + uci set network.bat0_hardif_eth0.proto='batadv_hardif' + uci set network.bat0_hardif_eth0.master='bat0' + uci set network.bat0_hardif_eth0.mtu='1536' + uci set network.bat0_hardif_eth0.device='eth0' + + uci set network.bat0_lan=interface + uci set network.bat0_lan.proto='static' + uci set network.bat0_lan.ipaddr=$ipaddr + uci set network.bat0_lan.netmask='255.255.255.0' + uci set network.bat0_lan.ip6assign='60' + uci set network.bat0_lan.device='bat0' + uci commit network +} + +cmd=$1 +if [ -z $cmd ]; then + WW=$(uci get wireless.wmesh) + if [ -z $WW ]; then + loadmesh + reboot -f + else + loadconfig + /usr/lib/mesh/ping.sh & + fi +else + loadmesh +fi + +return diff --git a/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/ping.sh b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/ping.sh new file mode 100644 index 0000000..c29fbec --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/ping.sh @@ -0,0 +1,34 @@ +#!/bin/sh +. /lib/functions.sh + +pinging() { + PING=0 + RETURN_CODE_1=$(curl -m 10 -s -o /dev/null -w "%{http_code}" http://www.google.com/) + RETURN_CODE_2=$(curl -m 10 -s -o /dev/null -w "%{http_code}" http://www.example.org/) + RETURN_CODE_3=$(curl -m 10 -s -o /dev/null -w "%{http_code}" https://github.com) + + if [[ "$RETURN_CODE_1" != "200" && "$RETURN_CODE_2" != "200" && "$RETURN_CODE_3" != "200" ]]; then + PING=1 + fi +} + +gateway() { + mode=$1 +# batman-adv gateway handling (DHCP mangling) + [ "$(uci -q get batman-adv.bat0.gw_mode)" == "client" ] || return + if grep -q "^=>" /sys/kernel/debug/batman_adv/bat0/gateways ; then + BATTYPE=gw BATACTION=$mode /etc/hotplug.d/net/99-batman-gw + fi +} + +while true ; do + sleep 20 + pinging + if [ $PING -eq 1 ]; then + gateway add + batctl gw_mode client + else + gateway del + batctl gw_mode server 10000 + fi +done \ No newline at end of file diff --git a/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/radio.sh b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/radio.sh new file mode 100644 index 0000000..0ba8076 --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/radio.sh @@ -0,0 +1,78 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Radio" "$@" +} + +count_radio() { + local config=$1 + local channel + + config_get channel $1 channel + count=$((${count}+1)) +} + +do_radio() { + local config=$1 + local channel + + config_get channel $1 channel + rn=${config#radio} + freq="1" + if [ $channel -lt 15 ]; then + freq="0" + fi + iwin=$(iw phy phy$rn info) + hw=0 + hwt=$(echo "$iwin" | grep 'short GI for 40 MHz') + if [ ! -z "$hwt" ]; then + hw=1 + fi + hwt=$(echo "$iwin" | grep 'short GI (80 MHz)') + if [ ! -z "$hwt" ]; then + hw=2 + fi + hwt=$(echo "$iwin" | grep 'short GI (160') + if [ ! -z "$hwt" ]; then + hw=3 + fi + echo "$freq|$rn|$hw" >> /tmp/radiolist +} + +count=0 +rm -f /tmp/radiolist +config_load wireless +config_foreach count_radio wifi-device +if [ $count -gt 0 ]; then + echo "$count" > /tmp/radiolist + config_foreach do_radio wifi-device +fi + +CF1=$(uci -q get mesh.radio.radionumber) +CF2=$(uci -q get mesh.radio.channelindex) +CF3=$(uci -q get mesh.radio.channellist) +CF4=$(uci -q get mesh.radio.channelwidth) +CF5=$(uci -q get mesh.radio.usedfs) +CF6=$(uci -q get mesh.radio.dedicated) +echo "$CF1" >> /tmp/radiolist +echo "$CF2" >> /tmp/radiolist +echo "$CF3" >> /tmp/radiolist +echo "$CF4" >> /tmp/radiolist +echo "$CF5" >> /tmp/radiolist +echo "$CF6" >> /tmp/radiolist + +CF1=$(uci -q get mesh.network.networkid) +CF2=$(uci -q get mesh.network.netencrypted) +CF3=$(uci -q get mesh.network.netpassword) +echo "$CF1" >> /tmp/radiolist +echo "$CF2" >> /tmp/radiolist +echo "$CF3" >> /tmp/radiolist + +CF1=$(uci -q get mesh.roam.signalenable) +CF2=$(uci -q get mesh.roam.signalid) +echo "$CF1" >> /tmp/radiolist +echo "$CF2" >> /tmp/radiolist + + + diff --git a/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/save.sh b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/save.sh new file mode 100644 index 0000000..d050c7d --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/save.sh @@ -0,0 +1,25 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Save" "$@" +} + +state=$1 + +state=$(echo "$state" | tr "|" ",") +uci set mesh.radio.radionumber=$(echo "$state" | cut -d, -f1) +uci set mesh.radio.channelindex=$(echo "$state" | cut -d, -f2) +uci set mesh.radio.channellist=$(echo "$state" | cut -d, -f3) +uci set mesh.radio.usedfs=$(echo "$state" | cut -d, -f4) +uci set mesh.radio.channelwidth=$(echo "$state" | cut -d, -f5) +uci set mesh.radio.dedicated=$(echo "$state" | cut -d, -f6) + +uci set mesh.network.networkid=$(echo "$state" | cut -d, -f7) +uci set mesh.network.netencrypted=$(echo "$state" | cut -d, -f8) +uci set mesh.network.netpassword=$(echo "$state" | cut -d, -f9) + +uci set mesh.roam.signalenable=$(echo "$state" | cut -d, -f10) +uci set mesh.roam.signalid=$(echo "$state" | cut -d, -f11) + +uci commit mesh diff --git a/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/savecfg.sh b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/savecfg.sh new file mode 100644 index 0000000..bd4bf1f --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/savecfg.sh @@ -0,0 +1,16 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Save" "$@" +} + +state=$1 + +PKI_DIR="/www" +cd ${PKI_DIR} +mkdir -p package +cd .. +chmod -R 0777 ${PKI_DIR}/package + +echo "$state" > ${PKI_DIR}/package/meshcfg.meshcfg \ No newline at end of file diff --git a/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/startstop.sh b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/startstop.sh new file mode 100644 index 0000000..2cd290a --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/usr/lib/mesh/startstop.sh @@ -0,0 +1,8 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Start Mesh" "$@" +} + +/usr/lib/mesh/checker.sh 1 \ No newline at end of file diff --git a/rooter/0mesh/mesh-mesh/files/www/luci-static/resources/dracula/dracula_graffle.js b/rooter/0mesh/mesh-mesh/files/www/luci-static/resources/dracula/dracula_graffle.js new file mode 100644 index 0000000..9832727 --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/www/luci-static/resources/dracula/dracula_graffle.js @@ -0,0 +1 @@ +Raphael.fn.connection=function(a,b,c){var d=this,e={draw:function(){for(var f=a.getBBox(),g=b.getBBox(),h=0,i=0,j=[{x:f.x+f.width/2,y:f.y-h},{x:f.x+f.width/2,y:f.y+f.height+h},{x:f.x-h,y:f.y+f.height/2},{x:f.x+f.width+h,y:f.y+f.height/2},{x:g.x+g.width/2,y:g.y-i},{x:g.x+g.width/2,y:g.y+g.height+i},{x:g.x-i,y:g.y+g.height/2},{x:g.x+g.width+i,y:g.y+g.height/2}],k={},l=[],m=0;m<4;m++)for(var n=4;n<8;n++){var o=Math.abs(j[m].x-j[n].x),p=Math.abs(j[m].y-j[n].y);(m==n-4||(3!=m&&6!=n||j[m].xj[n].x)&&(0!=m&&5!=n||j[m].y>j[n].y)&&(1!=m&&4!=n||j[m].ye.width-20?c-e.width+20:0),g=a.clientY-(d<20?d-20:d>e.height-20?d-e.height+20:0);e.isDrag.set.translate(f-Math.round(e.isDrag.dx),g-Math.round(e.isDrag.dy));for(var h in e.graph.edges)e.graph.edges[h].connection&&e.graph.edges[h].connection.draw();e.isDrag.dx=f,e.isDrag.dy=g}},f.onmouseup=function(){e.isDrag&&e.isDrag.set.animate({"fill-opacity":.6},500),e.isDrag=!1},this.draw()},Graph.Renderer.Raphael.prototype={translate:function(a){return[(a[0]-this.graph.layoutMinX)*this.factorX+this.radius,(a[1]-this.graph.layoutMinY)*this.factorY+this.radius]},rotate:function(a,b,c){var d=b*Math.cos(c),e=b*Math.sin(c);return[a[0]+d,a[1]+e]},draw:function(){this.factorX=(this.width-2*this.radius)/(this.graph.layoutMaxX-this.graph.layoutMinX),this.factorY=(this.height-2*this.radius)/(this.graph.layoutMaxY-this.graph.layoutMinY);for(a in this.graph.nodes)this.drawNode(this.graph.nodes[a]);for(var a=0;ab&&(b=e),ed&&(d=f),fk&&(i=k),i<-k&&(i=-k),j>k&&(j=k),j<-k&&(j=-k),h.layoutPosX+=i,h.layoutPosY+=j,h.layoutForceX=0,h.layoutForceY=0}},layoutRepulsive:function(a,b){if("undefined"!=typeof a&&"undefined"!=typeof b){var c=b.layoutPosX-a.layoutPosX,d=b.layoutPosY-a.layoutPosY,e=c*c+d*d;if(e<.01){c=.1*Math.random()+.1,d=.1*Math.random()+.1;var e=c*c+d*d}var f=Math.sqrt(e);if(fthis.maxRepulsiveForceDistance&&(g=this.maxRepulsiveForceDistance,f=g*g);var h=(f-this.k*this.k)/this.k;void 0==a.attraction&&(a.attraction=1),h*=.5*Math.log(a.attraction)+1,c.layoutForceX-=h*d/g,c.layoutForceY-=h*e/g,b.layoutForceX+=h*d/g,b.layoutForceY+=h*e/g}},Graph.Layout.Ordered=function(a,b){this.graph=a,this.order=b,this.layout()},Graph.Layout.Ordered.prototype={layout:function(){this.layoutPrepare(),this.layoutCalcBounds()},layoutPrepare:function(a){for(i in this.graph.nodes){var b=this.graph.nodes[i];b.layoutPosX=0,b.layoutPosY=0}var c=0;for(i in this.order){var b=this.order[i];b.layoutPosX=c,b.layoutPosY=Math.random(),c++}},layoutCalcBounds:function(){var a=1/0,b=-(1/0),c=1/0,d=-(1/0);for(i in this.graph.nodes){var e=this.graph.nodes[i].layoutPosX,f=this.graph.nodes[i].layoutPosY;e>b&&(b=e),ed&&(d=f),f

                ";if(ag.childNodes[m]!=2){return null;}}an.svg=!(an.vml=an.type=="VML");aT[aY]=an[aY];an._id=0;an._oid=0;an.fn={};an.is=function(e,d){d=aZ.call(d);return((d=="object"||d=="undefined")&&typeof e==d)||(e==null&&d=="null")||aZ.call(aw.call(e).slice(8,-1))==d;};an.setWindow=function(d){au=d;L=au.document;};var aD=function(e){if(an.vml){var d=/^\s+|\s+$/g;aD=aj(function(R){var S;R=(R+at)[aP](d,at);try{var a0=new ActiveXObject("htmlfile");a0.write("");a0.close();S=a0.body;}catch(a2){S=createPopup().document.body;}var i=S.createTextRange();try{S.style.color=R;var a1=i.queryCommandValue("ForeColor");a1=((a1&255)<<16)|(a1&65280)|((a1&16711680)>>>16);return"#"+("000000"+a1[aA](16)).slice(-6);}catch(a2){return"none";}});}else{var E=L.createElement("i");E.title="Rapha\xebl Colour Picker";E.style.display="none";L.body[aL](E);aD=aj(function(i){E.style.color=i;return L.defaultView.getComputedStyle(E,at).getPropertyValue("color");});}return aD(e);};an.hsb2rgb=aj(function(a3,a1,a7){if(an.is(a3,"object")&&"h" in a3&&"s" in a3&&"b" in a3){a7=a3.b;a1=a3.s;a3=a3.h;}var R,S,a8;if(a7==0){return{r:0,g:0,b:0,hex:"#000"};}if(a3>1||a1>1||a7>1){a3/=255;a1/=255;a7/=255;}var a0=~~(a3*6),a4=(a3*6)-a0,E=a7*(1-a1),e=a7*(1-(a1*a4)),a9=a7*(1-(a1*(1-a4)));R=[a7,e,E,E,a9,a7,a7][a0];S=[a9,a7,a7,e,E,E,a9][a0];a8=[E,E,a9,a7,a7,e,E][a0];R*=255;S*=255;a8*=255;var a5={r:R,g:S,b:a8},d=(~~R)[aA](16),a2=(~~S)[aA](16),a6=(~~a8)[aA](16);d=d[aP](aU,"0");a2=a2[aP](aU,"0");a6=a6[aP](aU,"0");a5.hex="#"+d+a2+a6;return a5;},an);an.rgb2hsb=aj(function(d,e,a1){if(an.is(d,"object")&&"r" in d&&"g" in d&&"b" in d){a1=d.b;e=d.g;d=d.r;}if(an.is(d,"string")){var a3=an.getRGB(d);d=a3.r;e=a3.g;a1=a3.b;}if(d>1||e>1||a1>1){d/=255;e/=255;a1/=255;}var a0=g(d,e,a1),i=aI(d,e,a1),R,E,S=a0;if(i==a0){return{h:0,s:0,b:a0};}else{var a2=(a0-i);E=a2/a0;if(d==a0){R=(e-a1)/a2;}else{if(e==a0){R=2+((a1-d)/a2);}else{R=4+((d-e)/a2);}}R/=6;R<0&&R++;R>1&&R--;}return{h:R,s:E,b:S};},an);var aE=/,?([achlmqrstvxz]),?/gi;an._path2string=function(){return this.join(",")[aP](aE,"$1");};function aj(E,e,d){function i(){var R=Array[aY].slice.call(arguments,0),a0=R[az]("\u25ba"),S=i.cache=i.cache||{},a1=i.count=i.count||[];if(S[Q](a0)){return d?d(S[a0]):S[a0];}a1[m]>=1000&&delete S[a1.shift()];a1[f](a0);S[a0]=E[aW](e,R);return d?d(S[a0]):S[a0];}return i;}an.getRGB=aj(function(d){if(!d||!!((d=d+at).indexOf("-")+1)){return{r:-1,g:-1,b:-1,hex:"none",error:1};}if(d=="none"){return{r:-1,g:-1,b:-1,hex:"none"};}!(({hs:1,rg:1})[Q](d.substring(0,2))||d.charAt()=="#")&&(d=aD(d));var S,i,E,a2,a3,a0=d.match(x);if(a0){if(a0[2]){a2=G(a0[2].substring(5),16);E=G(a0[2].substring(3,5),16);i=G(a0[2].substring(1,3),16);}if(a0[3]){a2=G((a3=a0[3].charAt(3))+a3,16);E=G((a3=a0[3].charAt(2))+a3,16);i=G((a3=a0[3].charAt(1))+a3,16);}if(a0[4]){a0=a0[4][z](/\s*,\s*/);i=W(a0[0]);E=W(a0[1]);a2=W(a0[2]);}if(a0[5]){a0=a0[5][z](/\s*,\s*/);i=W(a0[0])*2.55;E=W(a0[1])*2.55;a2=W(a0[2])*2.55;}if(a0[6]){a0=a0[6][z](/\s*,\s*/);i=W(a0[0]);E=W(a0[1]);a2=W(a0[2]);return an.hsb2rgb(i,E,a2);}if(a0[7]){a0=a0[7][z](/\s*,\s*/);i=W(a0[0])*2.55;E=W(a0[1])*2.55;a2=W(a0[2])*2.55;return an.hsb2rgb(i,E,a2);}a0={r:i,g:E,b:a2};var e=(~~i)[aA](16),R=(~~E)[aA](16),a1=(~~a2)[aA](16);e=e[aP](aU,"0");R=R[aP](aU,"0");a1=a1[aP](aU,"0");a0.hex="#"+e+R+a1;return a0;}return{r:-1,g:-1,b:-1,hex:"none",error:1};},an);an.getColor=function(e){var i=this.getColor.start=this.getColor.start||{h:0,s:1,b:e||0.75},d=this.hsb2rgb(i.h,i.s,i.b);i.h+=0.075;if(i.h>1){i.h=0;i.s-=0.2;i.s<=0&&(this.getColor.start={h:0,s:1,b:i.b});}return d.hex;};an.getColor.reset=function(){delete this.start;};an.parsePathString=aj(function(d){if(!d){return null;}var i={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0},e=[];if(an.is(d,"array")&&an.is(d[0],"array")){e=av(d);}if(!e[m]){(d+at)[aP](/([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig,function(R,E,a1){var a0=[],S=aZ.call(E);a1[aP](/(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig,function(a3,a2){a2&&a0[f](+a2);});while(a0[m]>=i[S]){e[f]([E][aS](a0.splice(0,i[S])));if(!i[S]){break;}}});}e[aA]=an._path2string;return e;});an.findDotsAtSegment=function(e,d,be,bc,a0,R,a2,a1,a8){var a6=1-a8,a5=aM(a6,3)*e+aM(a6,2)*3*a8*be+a6*3*a8*a8*a0+aM(a8,3)*a2,a3=aM(a6,3)*d+aM(a6,2)*3*a8*bc+a6*3*a8*a8*R+aM(a8,3)*a1,ba=e+2*a8*(be-e)+a8*a8*(a0-2*be+e),a9=d+2*a8*(bc-d)+a8*a8*(R-2*bc+d),bd=be+2*a8*(a0-be)+a8*a8*(a2-2*a0+be),bb=bc+2*a8*(R-bc)+a8*a8*(a1-2*R+bc),a7=(1-a8)*e+a8*be,a4=(1-a8)*d+a8*bc,E=(1-a8)*a0+a8*a2,i=(1-a8)*R+a8*a1,S=(90-ab.atan((ba-bd)/(a9-bb))*180/ab.PI);(ba>bd||a91){bi=ab.sqrt(by)*bi;bg=ab.sqrt(by)*bg;}var E=bi*bi,br=bg*bg,bt=(a4==S?-1:1)*ab.sqrt(ab.abs((E*br-E*bn*bn-br*bo*bo)/(E*bn*bn+br*bo*bo))),bd=bt*bi*bn/bg+(a9+a8)/2,bc=bt*-bg*bo/bi+(bE+bD)/2,a3=ab.asin(((bE-bc)/bg).toFixed(7)),a2=ab.asin(((bD-bc)/bg).toFixed(7));a3=a9a2){a3=a3-R*2;}if(!S&&a2>a3){a2=a2-R*2;}}else{a3=bb[0];a2=bb[1];bd=bb[2];bc=bb[3];}var a7=a2-a3;if(ab.abs(a7)>bf){var be=a2,bh=a8,a5=bD;a2=a3+bf*(S&&a2>a3?1:-1);a8=bd+bi*ab.cos(a2);bD=bc+bg*ab.sin(a2);bm=K(a8,bD,bi,bg,ba,0,S,bh,a5,[a2,be,bd,bc]);}a7=a2-a3;var a1=ab.cos(a3),bC=ab.sin(a3),a0=ab.cos(a2),bB=ab.sin(a2),bp=ab.tan(a7/4),bs=4/3*bi*bp,bq=4/3*bg*bp,bz=[a9,bE],bx=[a9+bs*bC,bE-bq*a1],bw=[a8+bs*bB,bD-bq*a0],bu=[a8,bD];bx[0]=2*bz[0]-bx[0];bx[1]=2*bz[1]-bx[1];if(bb){return[bx,bw,bu][aS](bm);}else{bm=[bx,bw,bu][aS](bm)[az]()[z](",");var bk=[];for(var bv=0,bl=bm[m];bv1000000000000&&(a0=0.5);ab.abs(S)>1000000000000&&(S=0.5);if(a0>0&&a0<1){e=M(i,d,R,E,a9,a8,a5,a2,a0);a6[f](e.x);a3[f](e.y);}if(S>0&&S<1){e=M(i,d,R,E,a9,a8,a5,a2,S);a6[f](e.x);a3[f](e.y);}a7=(a8-2*E+d)-(a2-2*a8+E);a4=2*(E-d)-2*(a8-E);a1=d-E;a0=(-a4+ab.sqrt(a4*a4-4*a7*a1))/2/a7;S=(-a4-ab.sqrt(a4*a4-4*a7*a1))/2/a7;ab.abs(a0)>1000000000000&&(a0=0.5);ab.abs(S)>1000000000000&&(S=0.5);if(a0>0&&a0<1){e=M(i,d,R,E,a9,a8,a5,a2,a0);a6[f](e.x);a3[f](e.y);}if(S>0&&S<1){e=M(i,d,R,E,a9,a8,a5,a2,S);a6[f](e.x);a3[f](e.y);}return{min:{x:aI[aW](0,a6),y:aI[aW](0,a3)},max:{x:g[aW](0,a6),y:g[aW](0,a3)}};}),H=aj(function(a9,a4){var R=r(a9),a5=a4&&r(a4),a6={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},d={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},a0=function(ba,bb){var i,bc;if(!ba){return["C",bb.x,bb.y,bb.x,bb.y,bb.x,bb.y];}!(ba[0] in {T:1,Q:1})&&(bb.qx=bb.qy=null);switch(ba[0]){case"M":bb.X=ba[1];bb.Y=ba[2];break;case"A":ba=["C"][aS](K[aW](0,[bb.x,bb.y][aS](ba.slice(1))));break;case"S":i=bb.x+(bb.x-(bb.bx||bb.x));bc=bb.y+(bb.y-(bb.by||bb.y));ba=["C",i,bc][aS](ba.slice(1));break;case"T":bb.qx=bb.x+(bb.x-(bb.qx||bb.x));bb.qy=bb.y+(bb.y-(bb.qy||bb.y));ba=["C"][aS](aK(bb.x,bb.y,bb.qx,bb.qy,ba[1],ba[2]));break;case"Q":bb.qx=ba[1];bb.qy=ba[2];ba=["C"][aS](aK(bb.x,bb.y,ba[1],ba[2],ba[3],ba[4]));break;case"L":ba=["C"][aS](aX(bb.x,bb.y,ba[1],ba[2]));break;case"H":ba=["C"][aS](aX(bb.x,bb.y,ba[1],bb.y));break;case"V":ba=["C"][aS](aX(bb.x,bb.y,bb.x,ba[1]));break;case"Z":ba=["C"][aS](aX(bb.x,bb.y,bb.X,bb.Y));break;}return ba;},e=function(ba,bb){if(ba[bb][m]>7){ba[bb].shift();var bc=ba[bb];while(bc[m]){ba.splice(bb++,0,["C"][aS](bc.splice(0,6)));}ba.splice(bb,1);a7=g(R[m],a5&&a5[m]||0);}},E=function(be,bd,bb,ba,bc){if(be&&bd&&be[bc][0]=="M"&&bd[bc][0]!="M"){bd.splice(bc,0,["M",ba.x,ba.y]);bb.bx=0;bb.by=0;bb.x=be[bc][1];bb.y=be[bc][2];a7=g(R[m],a5&&a5[m]||0);}};for(var a2=0,a7=g(R[m],a5&&a5[m]||0);a23){return{container:1,x:arguments[0],y:arguments[1],width:arguments[2],height:arguments[3]};}}},aG=function(d,i){var e=this;for(var E in i){if(i[Q](E)&&!(E in d)){switch(typeof i[E]){case"function":(function(R){d[E]=d===e?R:function(){return R[aW](e,arguments);};})(i[E]);break;case"object":d[E]=d[E]||{};aG.call(this,d[E],i[E]);break;default:d[E]=i[E];break;}}}},ak=function(d,e){d==e.top&&(e.top=d.prev);d==e.bottom&&(e.bottom=d.next);d.next&&(d.next.prev=d.prev);d.prev&&(d.prev.next=d.next);},Y=function(d,e){if(e.top===d){return;}ak(d,e);d.next=null;d.prev=e.top;e.top.next=d;e.top=d;},k=function(d,e){if(e.bottom===d){return;}ak(d,e);d.next=e.bottom;d.prev=null;e.bottom.prev=d;e.bottom=d;},A=function(e,d,i){ak(e,i);d==i.top&&(i.top=e);d.next&&(d.next.prev=e);e.next=d.next;e.prev=d;d.next=e;},aq=function(e,d,i){ak(e,i);d==i.bottom&&(i.bottom=e);d.prev&&(d.prev.next=e);e.prev=d.prev;d.prev=e;e.next=d;},s=function(d){return function(){throw new Error("Rapha\xebl: you are calling to method \u201c"+d+"\u201d of removed object");};},ar=/^r(?:\(([^,]+?)\s*,\s*([^\)]+?)\))?/;if(an.svg){aT[aY].svgns="http://www.w3.org/2000/svg";aT[aY].xlink="http://www.w3.org/1999/xlink";var O=function(d){return +d+(~~d===d)*0.5;},V=function(S){for(var e=0,E=S[m];e0.5)*2-1);aM(a1-0.5,2)+aM(S-0.5,2)>0.25&&(S=ab.sqrt(0.25-aM(a1-0.5,2))*ba+0.5)&&S!=0.5&&(S=S.toFixed(5)-0.00001*ba);}return at;});a7=a7[z](/\s*\-\s*/);if(a4=="linear"){var a0=a7.shift();a0=-W(a0);if(isNaN(a0)){return null;}var R=[0,0,ab.cos(a0*ab.PI/180),ab.sin(a0*ab.PI/180)],a6=1/(g(ab.abs(R[2]),ab.abs(R[3]))||1);R[2]*=a6;R[3]*=a6;if(R[2]<0){R[0]=-R[2];R[2]=0;}if(R[3]<0){R[1]=-R[3];R[3]=0;}}var a3=p(a7);if(!a3){return null;}var e=aJ(a4+"Gradient");e.id="r"+(an._id++)[aA](36);aJ(e,a4=="radial"?{fx:a1,fy:S}:{x1:R[0],y1:R[1],x2:R[2],y2:R[3]});d.defs[aL](e);for(var a2=0,a8=a3[m];a2a1.height)&&(a1.height=a0.y+a0.height-a1.y);(a0.x+a0.width-a1.x>a1.width)&&(a1.width=a0.x+a0.width-a1.x);}}E&&this.hide();return a1;};ax[aY].attr=function(){if(this.removed){return this;}if(arguments[m]==0){var R={};for(var E in this.attrs){if(this.attrs[Q](E)){R[E]=this.attrs[E];}}this._.rt.deg&&(R.rotation=this.rotate());(this._.sx!=1||this._.sy!=1)&&(R.scale=this.scale());R.gradient&&R.fill=="none"&&(R.fill=R.gradient)&&delete R.gradient;return R;}if(arguments[m]==1&&an.is(arguments[0],"string")){if(arguments[0]=="translation"){return t.call(this);}if(arguments[0]=="rotation"){return this.rotate();}if(arguments[0]=="scale"){return this.scale();}if(arguments[0]=="fill"&&this.attrs.fill=="none"&&this.attrs.gradient){return this.attrs.gradient;}return this.attrs[arguments[0]];}if(arguments[m]==1&&an.is(arguments[0],"array")){var d={};for(var e in arguments[0]){if(arguments[0][Q](e)){d[arguments[0][e]]=this.attrs[arguments[0][e]];}}return d;}if(arguments[m]==2){var S={};S[arguments[0]]=arguments[1];aa(this,S);}else{if(arguments[m]==1&&an.is(arguments[0],"object")){aa(this,arguments[0]);}}return this;};ax[aY].toFront=function(){if(this.removed){return this;}this.node.parentNode[aL](this.node);var d=this.paper;d.top!=this&&Y(this,d);return this;};ax[aY].toBack=function(){if(this.removed){return this;}if(this.node.parentNode.firstChild!=this.node){this.node.parentNode.insertBefore(this.node,this.node.parentNode.firstChild);k(this,this.paper);var d=this.paper;}return this;};ax[aY].insertAfter=function(d){if(this.removed){return this;}var e=d.node;if(e.nextSibling){e.parentNode.insertBefore(this.node,e.nextSibling);}else{e.parentNode[aL](this.node);}A(this,d,this.paper);return this;};ax[aY].insertBefore=function(d){if(this.removed){return this;}var e=d.node;e.parentNode.insertBefore(this.node,e);aq(this,d,this.paper);return this;};var P=function(e,d,S,R){d=O(d);S=O(S);var E=aJ("circle");e.canvas&&e.canvas[aL](E);var i=new ax(E,e);i.attrs={cx:d,cy:S,r:R,fill:"none",stroke:"#000"};i.type="circle";aJ(E,i.attrs);return i;};var aF=function(i,d,a1,e,S,a0){d=O(d);a1=O(a1);var R=aJ("rect");i.canvas&&i.canvas[aL](R);var E=new ax(R,i);E.attrs={x:d,y:a1,width:e,height:S,r:a0||0,rx:a0||0,ry:a0||0,fill:"none",stroke:"#000"};E.type="rect";aJ(R,E.attrs);return E;};var ai=function(e,d,a0,S,R){d=O(d);a0=O(a0);var E=aJ("ellipse");e.canvas&&e.canvas[aL](E);var i=new ax(E,e);i.attrs={cx:d,cy:a0,rx:S,ry:R,fill:"none",stroke:"#000"};i.type="ellipse";aJ(E,i.attrs);return i;};var o=function(i,a0,d,a1,e,S){var R=aJ("image");aJ(R,{x:d,y:a1,width:e,height:S,preserveAspectRatio:"none"});R.setAttributeNS(i.xlink,"href",a0);i.canvas&&i.canvas[aL](R);var E=new ax(R,i);E.attrs={x:d,y:a1,width:e,height:S,src:a0};E.type="image";return E;};var X=function(e,d,S,R){var E=aJ("text");aJ(E,{x:d,y:S,"text-anchor":"middle"});e.canvas&&e.canvas[aL](E);var i=new ax(E,e);i.attrs={x:d,y:S,"text-anchor":"middle",text:R,font:j.font,stroke:"none",fill:"#000"};i.type="text";aa(i,i.attrs);return i;};var aV=function(e,d){this.width=e||this.width;this.height=d||this.height;this.canvas[v]("width",this.width);this.canvas[v]("height",this.height);return this;};var w=function(){var E=ao[aW](null,arguments),i=E&&E.container,e=E.x,a0=E.y,R=E.width,d=E.height;if(!i){throw new Error("SVG container not found.");}var S=aJ("svg");R=R||512;d=d||342;aJ(S,{xmlns:"http://www.w3.org/2000/svg",version:1.1,width:R,height:d});if(i==1){S.style.cssText="position:absolute;left:"+e+"px;top:"+a0+"px";L.body[aL](S);}else{if(i.firstChild){i.insertBefore(S,i.firstChild);}else{i[aL](S);}}i=new aT;i.width=R;i.height=d;i.canvas=S;aG.call(i,i,an.fn);i.clear();return i;};aT[aY].clear=function(){var d=this.canvas;while(d.firstChild){d.removeChild(d.firstChild);}this.bottom=this.top=null;(this.desc=aJ("desc"))[aL](L.createTextNode("Created with Rapha\xebl"));d[aL](this.desc);d[aL](this.defs=aJ("defs"));};aT[aY].remove=function(){this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas);for(var d in this){this[d]=s(d);}};}if(an.vml){var aH=function(a8){var a5=/[ahqstv]/ig,a0=r;(a8+at).match(a5)&&(a0=H);a5=/[clmz]/g;if(a0==r&&!(a8+at).match(a5)){var e={M:"m",L:"l",C:"c",Z:"x",m:"t",l:"r",c:"v",z:"x"},R=/([clmz]),?([^clmz]*)/gi,S=/-?[^,\s-]+/g;var a4=(a8+at)[aP](R,function(a9,bb,i){var ba=[];i[aP](S,function(bc){ba[f](O(bc));});return e[bb]+ba;});return a4;}var a6=a0(a8),E,a4=[],d;for(var a2=0,a7=a6[m];a21&&(e=1);a7.opacity=e;}a8.fill&&(a7.on=true);if(a7.on==null||a8.fill=="none"){a7.on=false;}if(a7.on&&a8.fill){var i=a8.fill.match(c);if(i){a7.src=i[1];a7.type="tile";}else{a7.color=an.getRGB(a8.fill).hex;a7.src=at;a7.type="solid";if(an.getRGB(a8.fill).error&&(bd.type in {circle:1,ellipse:1}||(a8.fill+at).charAt()!="r")&&b(bd,a8.fill)){a9.fill="none";a9.gradient=a8.fill;}}}ba&&a6[aL](a7);var R=(a6.getElementsByTagName("stroke")&&a6.getElementsByTagName("stroke")[0]),bb=false;!R&&(bb=R=ah("stroke"));if((a8.stroke&&a8.stroke!="none")||a8["stroke-width"]||a8["stroke-opacity"]!=null||a8["stroke-dasharray"]||a8["stroke-miterlimit"]||a8["stroke-linejoin"]||a8["stroke-linecap"]){R.on=true;}(a8.stroke=="none"||R.on==null||a8.stroke==0||a8["stroke-width"]==0)&&(R.on=false);R.on&&a8.stroke&&(R.color=an.getRGB(a8.stroke).hex);var e=((+a9["stroke-opacity"]+1||2)-1)*((+a9.opacity+1||2)-1),a4=(W(a8["stroke-width"])||1)*0.75;e<0&&(e=0);e>1&&(e=1);a8["stroke-width"]==null&&(a4=a9["stroke-width"]);a8["stroke-width"]&&(R.weight=a4);a4&&a4<1&&(e*=a4)&&(R.weight=1);R.opacity=e;a8["stroke-linejoin"]&&(R.joinstyle=a8["stroke-linejoin"]||"miter");R.miterlimit=a8["stroke-miterlimit"]||8;a8["stroke-linecap"]&&(R.endcap=a8["stroke-linecap"]=="butt"?"flat":a8["stroke-linecap"]=="square"?"square":"round");if(a8["stroke-dasharray"]){var a5={"-":"shortdash",".":"shortdot","-.":"shortdashdot","-..":"shortdashdotdot",". ":"dot","- ":"dash","--":"longdash","- .":"dashdot","--.":"longdashdot","--..":"longdashdotdot"};R.dashstyle=a5[Q](a8["stroke-dasharray"])?a5[a8["stroke-dasharray"]]:at;}bb&&a6[aL](R);}if(bd.type=="text"){var a0=bd.paper.span.style;a9.font&&(a0.font=a9.font);a9["font-family"]&&(a0.fontFamily=a9["font-family"]);a9["font-size"]&&(a0.fontSize=a9["font-size"]);a9["font-weight"]&&(a0.fontWeight=a9["font-weight"]);a9["font-style"]&&(a0.fontStyle=a9["font-style"]);bd.node.string&&(bd.paper.span.innerHTML=(bd.node.string+at)[aP](/"));bd.W=a9.w=bd.paper.span.offsetWidth;bd.H=a9.h=bd.paper.span.offsetHeight;bd.X=a9.x;bd.Y=a9.y+O(bd.H/2);switch(a9["text-anchor"]){case"start":bd.node.style["v-text-align"]="left";bd.bbx=O(bd.W/2);break;case"end":bd.node.style["v-text-align"]="right";bd.bbx=-O(bd.W/2);break;default:bd.node.style["v-text-align"]="center";break;}}};var b=function(d,a1){d.attrs=d.attrs||{};var a2=d.attrs,a4=d.node.getElementsByTagName("fill"),S="linear",a0=".5 .5";d.attrs.gradient=a1;a1=(a1+at)[aP](ar,function(a6,a7,i){S="radial";if(a7&&i){a7=W(a7);i=W(i);aM(a7-0.5,2)+aM(i-0.5,2)>0.25&&(i=ab.sqrt(0.25-aM(a7-0.5,2))*((i>0.5)*2-1)+0.5);a0=a7+am+i;}return at;});a1=a1[z](/\s*\-\s*/);if(S=="linear"){var e=a1.shift();e=-W(e);if(isNaN(e)){return null;}}var R=p(a1);if(!R){return null;}d=d.shape||d.node;a4=a4[0]||ah("fill");if(R[m]){a4.on=true;a4.method="none";a4.type=(S=="radial")?"gradientradial":"gradient";a4.color=R[0].color;a4.color2=R[R[m]-1].color;var a5=[];for(var E=0,a3=R[m];E');};}catch(af){ah=function(d){return L.createElement("<"+d+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');};}var w=function(){var i=ao[aW](null,arguments),d=i.container,a2=i.height,a3,e=i.width,a1=i.x,a0=i.y;if(!d){throw new Error("VML container not found.");}var R=new aT,S=R.canvas=L.createElement("div"),E=S.style;e=e||512;a2=a2||342;e==+e&&(e+="px");a2==+a2&&(a2+="px");R.width=1000;R.height=1000;R.coordsize="1000 1000";R.coordorigin="0 0";R.span=L.createElement("span");R.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";S[aL](R.span);E.cssText=an.format("width:{0};height:{1};position:absolute;clip:rect(0 {0} {1} 0);overflow:hidden",e,a2);if(d==1){L.body[aL](S);E.left=a1+"px";E.top=a0+"px";}else{d.style.width=e;d.style.height=a2;if(d.firstChild){d.insertBefore(S,d.firstChild);}else{d[aL](S);}}aG.call(R,R,an.fn);return R;};aT[aY].clear=function(){this.canvas.innerHTML=at;this.span=L.createElement("span");this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";this.canvas[aL](this.span);this.bottom=this.top=null;};aT[aY].remove=function(){this.canvas.parentNode.removeChild(this.canvas);for(var d in this){this[d]=s(d);}};}if((/^Apple|^Google/).test(navigator.vendor)&&!(navigator.userAgent.indexOf("Version/4.0")+1)){aT[aY].safari=function(){var d=this.rect(-99,-99,this.width+99,this.height+99);setTimeout(function(){d.remove();});};}else{aT[aY].safari=function(){};}var ae=(function(){if(L.addEventListener){return function(R,i,e,d){var E=function(S){return e.call(d,S);};R.addEventListener(i,E,false);return function(){R.removeEventListener(i,E,false);return true;};};}else{if(L.attachEvent){return function(S,E,i,e){var R=function(a0){return i.call(e,a0||au.event);};S.attachEvent("on"+E,R);var d=function(){S.detachEvent("on"+E,R);return true;};return d;};}}})();for(var ac=F[m];ac--;){(function(d){ax[aY][d]=function(e){if(an.is(e,"function")){this.events=this.events||[];this.events.push({name:d,f:e,unbind:ae(this.shape||this.node,d,e,this)});}return this;};ax[aY]["un"+d]=function(E){var i=this.events,e=i[m];while(e--){if(i[e].name==d&&i[e].f==E){i[e].unbind();i.splice(e,1);!i.length&&delete this.events;return this;}}return this;};})(F[ac]);}ax[aY].hover=function(e,d){return this.mouseover(e).mouseout(d);};ax[aY].unhover=function(e,d){return this.unmouseover(e).unmouseout(d);};aT[aY].circle=function(d,i,e){return P(this,d||0,i||0,e||0);};aT[aY].rect=function(d,R,e,i,E){return aF(this,d||0,R||0,e||0,i||0,E||0);};aT[aY].ellipse=function(d,E,i,e){return ai(this,d||0,E||0,i||0,e||0);};aT[aY].path=function(d){d&&!an.is(d,"string")&&!an.is(d[0],"array")&&(d+=at);return q(an.format[aW](an,arguments),this);};aT[aY].image=function(E,d,R,e,i){return o(this,E||"about:blank",d||0,R||0,e||0,i||0);};aT[aY].text=function(d,i,e){return X(this,d||0,i||0,e||at);};aT[aY].set=function(d){arguments[m]>1&&(d=Array[aY].splice.call(arguments,0,arguments[m]));return new T(d);};aT[aY].setSize=aV;aT[aY].top=aT[aY].bottom=null;aT[aY].raphael=an;function u(){return this.x+am+this.y;}ax[aY].scale=function(a6,a5,E,e){if(a6==null&&a5==null){return{x:this._.sx,y:this._.sy,toString:u};}a5=a5||a6;!+a5&&(a5=a6);var ba,a8,a9,a7,bm=this.attrs;if(a6!=0){var a4=this.getBBox(),a1=a4.x+a4.width/2,R=a4.y+a4.height/2,bl=a6/this._.sx,bk=a5/this._.sy;E=(+E||E==0)?E:a1;e=(+e||e==0)?e:R;var a3=~~(a6/ab.abs(a6)),a0=~~(a5/ab.abs(a5)),be=this.node.style,bo=E+(a1-E)*bl,bn=e+(R-e)*bk;switch(this.type){case"rect":case"image":var a2=bm.width*a3*bl,bd=bm.height*a0*bk;this.attr({height:bd,r:bm.r*aI(a3*bl,a0*bk),width:a2,x:bo-a2/2,y:bn-bd/2});break;case"circle":case"ellipse":this.attr({rx:bm.rx*a3*bl,ry:bm.ry*a0*bk,r:bm.r*aI(a3*bl,a0*bk),cx:bo,cy:bn});break;case"path":var bg=ad(bm.path),bh=true;for(var bj=0,bc=bg[m];bjS){if(e&&!a8.start){a6=an.findDotsAtSegment(a5,a4,E[1],E[2],E[3],E[4],E[5],E[6],(S-a3)/a1);R+=["C",a6.start.x,a6.start.y,a6.m.x,a6.m.y,a6.x,a6.y];if(a0){return R;}a8.start=R;R=["M",a6.x,a6.y+"C",a6.n.x,a6.n.y,a6.end.x,a6.end.y,E[5],E[6]][az]();a3+=a1;a5=+E[5];a4=+E[6];continue;}if(!d&&!e){a6=an.findDotsAtSegment(a5,a4,E[1],E[2],E[3],E[4],E[5],E[6],(S-a3)/a1);return{x:a6.x,y:a6.y,alpha:a6.alpha};}}a3+=a1;a5=+E[5];a4=+E[6];}R+=E;}a8.end=R;a6=d?a3:e?a8:an.findDotsAtSegment(a5,a4,E[1],E[2],E[3],E[4],E[5],E[6],1);a6.alpha&&(a6={x:a6.x,y:a6.y,alpha:a6.alpha});return a6;};},n=aj(function(E,d,a0,S,a6,a5,a4,a3){var R={x:0,y:0},a2=0;for(var a1=0;a1<1.01;a1+=0.01){var e=M(E,d,a0,S,a6,a5,a4,a3,a1);a1&&(a2+=ab.sqrt(aM(R.x-e.x,2)+aM(R.y-e.y,2)));R=e;}return a2;});var ap=aB(1),C=aB(),J=aB(0,1);ax[aY].getTotalLength=function(){if(this.type!="path"){return;}return ap(this.attrs.path);};ax[aY].getPointAtLength=function(d){if(this.type!="path"){return;}return C(this.attrs.path,d);};ax[aY].getSubpath=function(i,e){if(this.type!="path"){return;}if(ab.abs(this.getTotalLength()-e)<0.000001){return J(this.attrs.path,i).end;}var d=J(this.attrs.path,e,1);return i?J(d,i).end:d;};an.easing_formulas={linear:function(d){return d;},"<":function(d){return aM(d,3);},">":function(d){return aM(d-1,3)+1;},"<>":function(d){d=d*2;if(d<1){return aM(d,3)/2;}d-=2;return(aM(d,3)+2)/2;},backIn:function(e){var d=1.70158;return e*e*((d+1)*e-d);},backOut:function(e){e=e-1;var d=1.70158;return e*e*((d+1)*e+d)+1;},elastic:function(i){if(i==0||i==1){return i;}var e=0.3,d=e/4;return aM(2,-10*i)*ab.sin((i-d)*(2*ab.PI)/e)+1;},bounce:function(E){var e=7.5625,i=2.75,d;if(E<(1/i)){d=e*E*E;}else{if(E<(2/i)){E-=(1.5/i);d=e*E*E+0.75;}else{if(E<(2.5/i)){E-=(2.25/i);d=e*E*E+0.9375;}else{E-=(2.625/i);d=e*E*E+0.984375;}}}return d;}};var I={length:0},aR=function(){var a2=+new Date;for(var be in I){if(be!="length"&&I[Q](be)){var bj=I[be];if(bj.stop){delete I[be];I[m]--;continue;}var a0=a2-bj.start,bb=bj.ms,ba=bj.easing,bf=bj.from,a7=bj.diff,E=bj.to,a6=bj.t,a9=bj.prev||0,a1=bj.el,R=bj.callback,a8={},d;if(a0255?255:(d<0?0:d);},t=function(d,i){if(d==null){return{x:this._.tx,y:this._.ty,toString:u};}this._.tx+=+d;this._.ty+=+i;switch(this.type){case"circle":case"ellipse":this.attr({cx:+d+this.attrs.cx,cy:+i+this.attrs.cy});break;case"rect":case"image":case"text":this.attr({x:+d+this.attrs.x,y:+i+this.attrs.y});break;case"path":var e=ad(this.attrs.path);e[0][1]+=+d;e[0][2]+=+i;this.attr({path:e});break;}return this;};ax[aY].animateWith=function(e,i,d,R,E){I[e.id]&&(i.start=I[e.id].start);return this.animate(i,d,R,E);};ax[aY].animateAlong=ay();ax[aY].animateAlongBack=ay(1);function ay(d){return function(E,i,e,S){var R={back:d};an.is(e,"function")?(S=e):(R.rot=e);E&&E.constructor==ax&&(E=E.attrs.path);E&&(R.along=E);return this.animate(R,i,S);};}ax[aY].onAnimation=function(d){this._run=d||0;return this;};ax[aY].animate=function(be,a5,a4,E){if(an.is(a4,"function")||!a4){E=a4||null;}var a9={},e={},a2={};for(var a6 in be){if(be[Q](a6)){if(Z[Q](a6)){a9[a6]=this.attr(a6);(a9[a6]==null)&&(a9[a6]=j[a6]);e[a6]=be[a6];switch(Z[a6]){case"along":var bc=ap(be[a6]),a7=C(be[a6],bc*!!be.back),R=this.getBBox();a2[a6]=bc/a5;a2.tx=R.x;a2.ty=R.y;a2.sx=a7.x;a2.sy=a7.y;e.rot=be.rot;e.back=be.back;e.len=bc;be.rot&&(a2.r=W(this.rotate())||0);break;case"number":a2[a6]=(e[a6]-a9[a6])/a5;break;case"colour":a9[a6]=an.getRGB(a9[a6]);var a8=an.getRGB(e[a6]);a2[a6]={r:(a8.r-a9[a6].r)/a5,g:(a8.g-a9[a6].g)/a5,b:(a8.b-a9[a6].b)/a5};break;case"path":var S=H(a9[a6],e[a6]);a9[a6]=S[0];var a3=S[1];a2[a6]=[];for(var bb=0,a1=a9[a6][m];bb)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
                a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

                ";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
                ";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
                ","
                "],thead:[1,"","
                "],tr:[2,"","
                "],td:[3,"","
                "],col:[2,"","
                "],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
                ","
                "];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
                ").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
                "; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/rooter/0mesh/mesh-mesh/files/www/luci-static/resources/protocol/batadv.js b/rooter/0mesh/mesh-mesh/files/www/luci-static/resources/protocol/batadv.js new file mode 100644 index 0000000..837ba18 --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/www/luci-static/resources/protocol/batadv.js @@ -0,0 +1,8 @@ +'use strict'; +'require network'; + +return network.registerProtocol('batadv', { + getI18n: function() { + return _('Batman'); + } +}); diff --git a/rooter/0mesh/mesh-mesh/files/www/luci-static/resources/protocol/batadv_hardif.js b/rooter/0mesh/mesh-mesh/files/www/luci-static/resources/protocol/batadv_hardif.js new file mode 100644 index 0000000..545e63d --- /dev/null +++ b/rooter/0mesh/mesh-mesh/files/www/luci-static/resources/protocol/batadv_hardif.js @@ -0,0 +1,8 @@ +'use strict'; +'require network'; + +return network.registerProtocol('batadv_hardif', { + getI18n: function() { + return _('Mesh'); + } +}); diff --git a/rooter/0mesh/mesh-wpad/Makefile b/rooter/0mesh/mesh-wpad/Makefile new file mode 100644 index 0000000..dcb961e --- /dev/null +++ b/rooter/0mesh/mesh-wpad/Makefile @@ -0,0 +1,29 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=mesh-wpad +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/mesh-wpad + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Mesh Support + DEPENDS:=+wpad-mesh-openssl + TITLE:=Support for Mesh routing + PKGARCH:=all +endef + +define Package/mesh-wpad/description + Helper scripts to install Meshing +endef + +define Build/Compile +endef + +$(eval $(call BuildPackage,mesh-wpad)) diff --git a/rooter/0optionalapps/bwallocate/Makefile b/rooter/0optionalapps/bwallocate/Makefile new file mode 100644 index 0000000..183c85d --- /dev/null +++ b/rooter/0optionalapps/bwallocate/Makefile @@ -0,0 +1,34 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=bwallocate +PKG_VERSION:=4.500 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/bwallocate + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + DEPENDS:=+ext-throttle +msmtp + TITLE:=Install scripts for Bandwidth Allocation + PKGARCH:=all +endef + +define Package/bwallocate/description + Install scripts for Bandwidth Allocation +endef + + +define Build/Compile +endef + +define Package/bwallocate/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,bwallocate)) diff --git a/rooter/0optionalapps/bwallocate/files/etc/init.d/textbwint b/rooter/0optionalapps/bwallocate/files/etc/init.d/textbwint new file mode 100644 index 0000000..b74e85a --- /dev/null +++ b/rooter/0optionalapps/bwallocate/files/etc/init.d/textbwint @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common + +START=88 + +log() { + logger -t "TEXTING" "$@" +} + +start() +{ + uci set bwmon.general.enabled="1" + uci commit bwmon + /usr/lib/bwmon/textbw.sh & +} diff --git a/rooter/0optionalapps/bwallocate/files/usr/lib/lua/luci/controller/bwallocate.lua b/rooter/0optionalapps/bwallocate/files/usr/lib/lua/luci/controller/bwallocate.lua new file mode 100644 index 0000000..a26d6fd --- /dev/null +++ b/rooter/0optionalapps/bwallocate/files/usr/lib/lua/luci/controller/bwallocate.lua @@ -0,0 +1,22 @@ +module("luci.controller.bwallocate", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local lock = luci.model.uci.cursor():get("custom", "menu", "full") + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + if lock == "1" then + local lock1 = luci.model.uci.cursor():get("custom", "bwallocate", "lock") + if lock1 == "1" then + if (multilock == "1" and rootlock == "1") then + entry({"admin", "adminmenu", "bwmenu"}, cbi("fullmenu/bwmenu"), translate("Bandwidth Allocation"), 6) + else + entry({"admin", "adminmenu", "bwmenu"}, cbi("fullmenu/bwmenu"), translate("---Bandwidth Allocation"), 6) + end + end + end + end +end \ No newline at end of file diff --git a/rooter/0optionalapps/bwallocate/files/usr/lib/lua/luci/model/cbi/fullmenu/bwmenu.lua b/rooter/0optionalapps/bwallocate/files/usr/lib/lua/luci/model/cbi/fullmenu/bwmenu.lua new file mode 100644 index 0000000..4b4d4ab --- /dev/null +++ b/rooter/0optionalapps/bwallocate/files/usr/lib/lua/luci/model/cbi/fullmenu/bwmenu.lua @@ -0,0 +1,267 @@ +local utl = require "luci.util" + +m = Map("custom", translate("Bandwidth Allocation"), translate("Set Maximum Bandwidth Usage before Internet blockage")) + +m.on_after_save = function(self) + luci.sys.call("/usr/lib/bwmon/allocate.sh 0 &") +end + +s = m:section(TypedSection, "bwallocate", translate("Allocation Settings")) +s.anonymous = true +s.addremove = false + +s:option(Flag, "enabled", translate("Allocation Enabled : ")) + +maxim = s:option(Value, "allocate", translate("Maximum Bandwidth in GB : "), translate("Maximum amount of bandwidth that can be used before Internet is affected")); +maxim.rmempty = true; +maxim.optional=false; +maxim.default="1000"; +maxim.datatype = "and(uinteger,min(1))" + +rollover = s:option(ListValue, "rollover", translate("Rollover Day : "), translate("Day of the month when bandwidth usage resets")) +rollover.rmempty = true +rollover:value("1", "1st") +rollover:value("2", "2nd") +rollover:value("3", "3rd") +rollover:value("4", "4th") +rollover:value("5", "5th") +rollover:value("6", "6th") +rollover:value("7", "7th") +rollover:value("8", "8th") +rollover:value("9", "9th") +rollover:value("10", "10th") +rollover:value("11", "11th") +rollover:value("12", "12th") +rollover:value("13", "13th") +rollover:value("14", "14th") +rollover:value("15", "15th") +rollover:value("16", "16th") +rollover:value("17", "17th") +rollover:value("18", "18th") +rollover:value("19", "19th") +rollover:value("20", "20th") +rollover:value("21", "21th") +rollover:value("22", "22th") +rollover:value("23", "23th") +rollover:value("24", "24th") +rollover:value("25", "25th") +rollover:value("26", "26th") +rollover:value("27", "27th") +rollover:value("28", "28th") +rollover.default = "1" + +act = s:option(ListValue, "action", translate("Internet Action : "), translate("Action taken when allocation is exceeded")) +act.rmempty = true +act:value("0", "Internet Blocked") +act:value("1", "Internet Throttled") +act.default = "0" + +down = s:option(Value, "down", translate("Download Speed in Mbps :")); +down.optional=false; +down.rmempty = true; +down.datatype = "and(uinteger,min(1),max(999))" +down:depends("action", "1") +down.default = "5" + +up = s:option(Value, "up", translate("Upload Speed in Mbps :")); +up.optional=false; +up.rmempty = true; +up.datatype = "and(uinteger,min(1),max(999))" +up:depends("action", "1") +up.default = "2" + +s = m:section(TypedSection, "texting", translate("Text/Email Settings")) +s.anonymous = true +s.addremove = false + +aact = s:option(ListValue, "text", translate("Enable : "), translate("Enable Sending Text or Email Information")) +aact.rmempty = true +aact:value("0", "No") +aact:value("1", "Yes") +aact.default = "0" + + +pph = s:option(Value, "ident", translate("Identifier :")); +pph.optional=false; +pph.rmempty = true; +pph:depends("text", "1") +pph.default = "xxx" + + + +ct = s:option(ListValue, "method", translate("Criteria : "), translate("Criteria used to determine when to send information")) +ct.rmempty = true +ct:value("0", translate("By Specified Time Interval")) +ct:value("1", translate("By Amount Used")) +ct:value("2", translate("By Percentage Used")) +ct.default = "0" +ct:depends("text", "1") + +sdhour = s:option(ListValue, "time", translate("Sending Time :"), translate("Time to send information")) +sdhour.rmempty = true +sdhour:value("0", "12:00 AM") +sdhour:value("1", "12:15 AM") +sdhour:value("2", "12:30 AM") +sdhour:value("3", "12:45 AM") +sdhour:value("4", "01:00 AM") +sdhour:value("5", "01:15 AM") +sdhour:value("6", "01:30 AM") +sdhour:value("7", "01:45 AM") +sdhour:value("8", "02:00 AM") +sdhour:value("9", "02:15 AM") +sdhour:value("10", "02:30 AM") +sdhour:value("11", "02:45 AM") +sdhour:value("12", "03:00 AM") +sdhour:value("13", "03:15 AM") +sdhour:value("14", "03:30 AM") +sdhour:value("15", "03:45 AM") +sdhour:value("16", "04:00 AM") +sdhour:value("17", "04:15 AM") +sdhour:value("18", "04:30 AM") +sdhour:value("19", "04:45 AM") +sdhour:value("20", "05:00 AM") +sdhour:value("21", "05:15 AM") +sdhour:value("22", "05:30 AM") +sdhour:value("23", "05:45 AM") +sdhour:value("24", "06:00 AM") +sdhour:value("25", "06:15 AM") +sdhour:value("26", "06:30 AM") +sdhour:value("27", "06:45 AM") +sdhour:value("28", "07:00 AM") +sdhour:value("29", "07:15 AM") +sdhour:value("30", "07:30 AM") +sdhour:value("31", "07:45 AM") +sdhour:value("32", "08:00 AM") +sdhour:value("33", "08:15 AM") +sdhour:value("34", "08:30 AM") +sdhour:value("35", "08:45 AM") +sdhour:value("36", "09:00 AM") +sdhour:value("37", "09:15 AM") +sdhour:value("38", "09:30 AM") +sdhour:value("39", "09:45 AM") +sdhour:value("40", "10:00 AM") +sdhour:value("41", "10:15 AM") +sdhour:value("42", "10:30 AM") +sdhour:value("43", "10:45 AM") +sdhour:value("44", "11:00 AM") +sdhour:value("45", "11:15 AM") +sdhour:value("46", "11:30 AM") +sdhour:value("47", "11:45 AM") +sdhour:value("48", "12:00 PM") +sdhour:value("49", "12:15 PM") +sdhour:value("50", "12:30 PM") +sdhour:value("51", "12:45 PM") +sdhour:value("52", "01:00 PM") +sdhour:value("53", "01:15 PM") +sdhour:value("54", "01:30 PM") +sdhour:value("55", "01:45 PM") +sdhour:value("56", "02:00 PM") +sdhour:value("57", "02:15 PM") +sdhour:value("58", "02:30 PM") +sdhour:value("59", "02:45 PM") +sdhour:value("60", "03:00 PM") +sdhour:value("61", "03:15 PM") +sdhour:value("62", "03:30 PM") +sdhour:value("63", "03:45 PM") +sdhour:value("64", "04:00 PM") +sdhour:value("65", "04:15 PM") +sdhour:value("66", "04:30 PM") +sdhour:value("67", "04:45 PM") +sdhour:value("68", "05:00 PM") +sdhour:value("69", "05:15 PM") +sdhour:value("70", "05:30 PM") +sdhour:value("71", "05:45 PM") +sdhour:value("72", "06:00 PM") +sdhour:value("73", "06:15 PM") +sdhour:value("74", "06:30 PM") +sdhour:value("75", "06:45 PM") +sdhour:value("76", "07:00 PM") +sdhour:value("77", "07:15 PM") +sdhour:value("78", "07:30 PM") +sdhour:value("79", "07:45 PM") +sdhour:value("80", "08:00 PM") +sdhour:value("81", "08:15 PM") +sdhour:value("82", "08:30 PM") +sdhour:value("83", "08:45 PM") +sdhour:value("84", "09:00 PM") +sdhour:value("85", "09:15 PM") +sdhour:value("86", "09:30 PM") +sdhour:value("87", "09:45 PM") +sdhour:value("88", "10:00 PM") +sdhour:value("89", "10:15 PM") +sdhour:value("90", "10:30 PM") +sdhour:value("91", "10:45 PM") +sdhour:value("92", "11:00 PM") +sdhour:value("93", "11:15 PM") +sdhour:value("94", "11:30 PM") +sdhour:value("95", "11:45 PM") +sdhour:depends("text", "1") +sdhour.default = "48" + +xct = s:option(ListValue, "days", translate("Interval : "), translate("Number of days between sending information")) +xct.rmempty = true +xct:value("1", translate("Every Day")) +xct:value("2", translate("Every 2 Days")) +xct:value("5", translate("Every 5 Days")) +xct:value("10", translate("Every 10 Days")) +xct:value("15", translate("Every 15 Days")) +xct.default = "5" +xct:depends("method", "0") + +xxct = s:option(ListValue, "increment", translate("Increment : "), translate("Amount Used between sending information")) +xxct.rmempty = true +xxct:value("50", translate("Every 50 GB")) +xxct:value("75", translate("Every 75 GB")) +xxct:value("100", translate("Every 100 GB")) +xxct.default = "50" +xxct:depends("method", "1") + +ph1 = s:option(ListValue, "percent", translate("Percentage Used :")); +ph1.optional=false; +ph1.rmempty = true; +ph1:value("10", translate("10%")) +ph1:value("20", translate("20%")) +ph1:value("30", translate("30%")) +ph1:value("40", translate("40%")) +ph1:value("50", translate("50%")) +ph1:value("60", translate("60%")) +ph1:value("70", translate("70%")) +ph1:value("80", translate("80%")) +ph1:value("90", translate("90%")) +ph1:depends("method", "2") +ph1.default = "90" + +--b3 = s:option(DummyValue, "blank", " "); + +btn = s:option(Button, "_btn", translate(" ")) +btn.inputtitle = translate("Send Test of Text or Email") +btn.inputstyle = "apply" +btn:depends("text", "1") +function btn.write() + luci.sys.call("/usr/lib/bwmon/dotext.sh") +end + +b4 = s:option(DummyValue, "blank", " "); + +ct = s:option(ListValue, "tore", translate("Sending Method : "), translate("Method used to send information")) +ct.rmempty = true +ct:value("0", translate("By Text")) +ct:value("1", translate("By Email")) +ct.default = "0" +ct:depends("text", "1") + +ph = s:option(Value, "phone", translate("Phone Number :")); +ph.optional=false; +ph.rmempty = true; +ph.datatype = "phonedigit" +ph:depends("tore", "0") +ph.default = "12223334444" + +ph1 = s:option(Value, "email", translate("Email Address :")); +ph1.optional=false; +ph1.rmempty = true; +ph1:depends("tore", "1") +ph1.default = "jdoe@domain.com" + + +return m \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/Makefile b/rooter/0optionalapps/bwmon/Makefile new file mode 100644 index 0000000..c413b2f --- /dev/null +++ b/rooter/0optionalapps/bwmon/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=bwmon +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/bwmon + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + TITLE:=Install Bandwidth Monitor + PKGARCH:=all +endef + +define Package/bwmon/description + Helper scripts to install Bandwidth Monitor on ROOter +endef + + +define Build/Compile +endef + +define Package/bwmon/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,bwmon)) diff --git a/rooter/0optionalapps/bwmon/files/etc/config/bwmon b/rooter/0optionalapps/bwmon/files/etc/config/bwmon new file mode 100644 index 0000000..9d45a80 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/etc/config/bwmon @@ -0,0 +1,9 @@ + +config general 'general' + option external '0' + option backup '30' + option enabled '1' + + +config bwwan 'bwwan' + option wan '0' \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/etc/init.d/bwmon b/rooter/0optionalapps/bwmon/files/etc/init.d/bwmon new file mode 100644 index 0000000..925a8ea --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/etc/init.d/bwmon @@ -0,0 +1,18 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +START=60 + +start() { + WX=$(uci -q get custom.bwallocate.lock) + if [ "$WX" = "1" ]; then + uci set bwmon.general.enabled=$enable + uci commit bwmon + fi + /usr/lib/bwmon/wrtbwmon.sh & + /usr/lib/bwmon/create.sh & +} + +stop() { + rmdir -f /tmp/WRTbmon +} \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/lib/upgrade/keep.d/bwmon b/rooter/0optionalapps/bwmon/files/lib/upgrade/keep.d/bwmon new file mode 100644 index 0000000..c664559 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/lib/upgrade/keep.d/bwmon @@ -0,0 +1 @@ +/usr/lib/bwmon/data/ diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/allocate.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/allocate.sh new file mode 100644 index 0000000..58b4c22 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/allocate.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +log() { + logger -t "allocate" "$@" +} + +amount=$1 + +if [ $amount != "0" ]; then + uci set custom.bwallocate.allocate=$amount + uci commit custom +else + sleep 3 +fi +result=`ps | grep -i "create_data.lua" | grep -v "grep" | wc -l` +while [ $result -ge 1 ]; do + sleep 2 + result=`ps | grep -i "create_data.lua" | grep -v "grep" | wc -l` +done + +lua /usr/lib/bwmon/create_data.lua diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/amtleft.lua b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/amtleft.lua new file mode 100644 index 0000000..ee530db --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/amtleft.lua @@ -0,0 +1,30 @@ +#!/usr/bin/lua + +function ltrim(s) + return s:match'^%s*(.*)' +end + +function calc(total) + if total < 1000 then + tstr = string.format("%.2f", total) + tfm = " K" + else + if total < 1000000 then + tstr = string.format("%.2f", total/1000) + tfm = " MB" + else + tstr = string.format("%.2f", total/1000000) + tfm = " GB" + end + end + str = tstr .. tfm + return ltrim(str) +end + +aamt = arg[1] +uamt = arg[2] +amt = aamt - uamt +amts = calc(amt) +tfile = io.open("/tmp/amtleft", "w") +tfile:write(amts, "\n") +tfile:close() \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup-daily.lua b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup-daily.lua new file mode 100644 index 0000000..c9f579e --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup-daily.lua @@ -0,0 +1,61 @@ +#!/usr/bin/lua + +dailyUsageDB = arg[1] + +bw = {} +maclist = {} + +file = io.open(dailyUsageDB, "r") +i = 0 +repeat + line = file:read("*line") + if line == nil then + break + end + s, e = line:find("\"mac\":\"") + bs, be = line:find("\"", e+1) + mac = line:sub(e+1, bs-1) + if bw[mac] == nil then + maclist[i] = mac + i = i + 1 + bw[mac] = {} + bw[mac]['down'] = 0 + bw[mac]['offdown'] = 0 + bw[mac]['up'] = 0 + bw[mac]['offup'] = 0 + end + s, e = line:find("\"down\":\"") + bs, be = line:find("\"", e+1) + down = tonumber(line:sub(e+1, bs-1)) + bw[mac]['down'] = bw[mac]['down'] + down + s, e = line:find("\"up\":\"") + bs, be = line:find("\"", e+1) + up = tonumber(line:sub(e+1, bs-1)) + bw[mac]['up'] = bw[mac]['up'] + up + s, e = line:find("\"offdown\":\"") + bs, be = line:find("\"", e+1) + offdown = tonumber(line:sub(e+1, bs-1)) + bw[mac]['offdown'] = bw[mac]['offdown'] + offdown + s, e = line:find("\"offup\":\"") + bs, be = line:find("\"", e+1) + offup = tonumber(line:sub(e+1, bs-1)) + bw[mac]['offup'] = bw[mac]['offup'] + offup + s, e = line:find("\"ip\":\"") + bs, be = line:find("\"", e+1) + bw[mac]['ip'] = line:sub(e+1, bs-1) + s, e = line:find("\"name\":\"") + bs, be = line:find("\"", e+1) + bw[mac]['name'] = line:sub(e+1, bs-1) +until 1==0 +file:close() + +j=0 +file = io.open(dailyUsageDB .. ".bk", "w") +while maclist[j] ~= nil do + mac = maclist[j] + dline = "\"mac\":\"" .. mac .. "\",\"down\":\"" .. bw[mac]['down'] .. "\",\"up\":\"" .. bw[mac]['up'] .. "\",\"offdown\":\"0\",\"offup\":\"0\",\"ip\":\"" .. bw[mac]['ip'] .. "\",\"name\":\"" .. bw[mac]['name'] .. "\"" + file:write(dline, "\n") + j = j + 1 +end +file:close() + diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup-mon.lua b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup-mon.lua new file mode 100644 index 0000000..5d8e883 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup-mon.lua @@ -0,0 +1,81 @@ +#!/usr/bin/lua + +monthUsageDB = arg[1] + +tfile = io.open(monthUsageDB .. ".bk", "w") +tfile:close() + +file = io.open(monthUsageDB, "r") + +repeat + line = file:read("*line") + if line == nil then + break + end + s, e = line:find("start day") + if s ~= nil then + maclist = {} + bw = {} + i = 0 + startday = line + repeat + line = file:read("*line") + if line == nil then + break + end + s, e = line:find("end day") + if s ~= nil then + endday = line + break + end + s, e = line:find("\"mac\":\"") + bs, be = line:find("\"", e+1) + mac = line:sub(e+1, bs-1) + if bw[mac] == nil then + maclist[i] = mac + i = i + 1 + bw[mac] = {} + bw[mac]['down'] = 0 + bw[mac]['offdown'] = 0 + bw[mac]['up'] = 0 + bw[mac]['offup'] = 0 + end + s, e = line:find("\"down\":\"") + bs, be = line:find("\"", e+1) + down = tonumber(line:sub(e+1, bs-1)) + bw[mac]['down'] = bw[mac]['down'] + down + s, e = line:find("\"up\":\"") + bs, be = line:find("\"", e+1) + up = tonumber(line:sub(e+1, bs-1)) + bw[mac]['up'] = bw[mac]['up'] + up + s, e = line:find("\"offdown\":\"") + bs, be = line:find("\"", e+1) + offdown = tonumber(line:sub(e+1, bs-1)) + bw[mac]['offdown'] = bw[mac]['offdown'] + offdown + s, e = line:find("\"offup\":\"") + bs, be = line:find("\"", e+1) + offup = tonumber(line:sub(e+1, bs-1)) + bw[mac]['offup'] = bw[mac]['offup'] + offup + s, e = line:find("\"ip\":\"") + bs, be = line:find("\"", e+1) + bw[mac]['ip'] = line:sub(e+1, bs-1) + s, e = line:find("\"name\":\"") + bs, be = line:find("\"", e+1) + bw[mac]['name'] = line:sub(e+1, bs-1) + until 1==0 + -- day data + j=0 + tfile = io.open(monthUsageDB .. ".bk", "a") + tfile:write(startday, "\n") + while maclist[j] ~= nil do + mac = maclist[j] + dline = "\"mac\":\"" .. mac .. "\",\"down\":\"" .. bw[mac]['down'] .. "\",\"up\":\"" .. bw[mac]['up'] .. "\",\"offdown\":\"0\",\"offup\":\"0\",\"ip\":\"" .. bw[mac]['ip'] .. "\",\"name\":\"" .. bw[mac]['name'] .. "\"" + tfile:write(dline, "\n") + j = j + 1 + end + tfile:write(endday, "\n") + tfile:close() + end + +until 1==0 +file:close() \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup.sh new file mode 100644 index 0000000..dba2368 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/backup.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +log() { + logger -t "wrtbwmon" "$@" +} + +# parameters +# +btype=$1 +cDay=$2 +monthlyUsageDB=$3 +dailyUsageDB=$4 +monthlyUsageBack=$5 +dailyUsageBack=$6 +pDay=$7 + +/usr/lib/bwmon/backup-daily.lua $dailyUsageDB +/usr/lib/bwmon/backup-mon.lua $monthlyUsageDB +cp -f $monthlyUsageDB".bk" $monthlyUsageDB +cp -f $dailyUsageDB".bk" $dailyUsageDB + +echo "start day $cDay" >> $monthlyUsageDB".bk" +cat $dailyUsageDB".bk" >> $monthlyUsageDB".bk" +echo "end day $cDay" >> $monthlyUsageDB".bk" + +enb=$(uci -q get bwmon.general.enabled) + +if [ $btype = "backup" ]; then + if [ "$enb" = "1" ]; then + cp -f $monthlyUsageDB".bk" $monthlyUsageBack + cp -f $dailyUsageDB".bk" $dailyUsageBack + fi +else + if [ $btype = "daily" ]; then + cp -f $monthlyUsageDB".bk" $monthlyUsageDB + if [ "$enb" = "1" ]; then + cp -f $monthlyUsageDB".bk" $monthlyUsageBack + fi + fi +fi + +rm -f $dailyUsageDB".bk" + +bwday=$(uci -q get modem.modeminfo1.bwday) +if [ ! -z "$bwday" ]; then + if [ $bwday = $pDay -a $bwday != "0" ]; then + if [ -e /usr/lib/bwmon/sendsms ]; then + /usr/lib/bwmon/sendsms.sh + fi + fi +fi \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/block b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/block new file mode 100644 index 0000000..ba7fb02 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/block @@ -0,0 +1,28 @@ +#!/bin/sh + +internet_block() +{ + enable=$1 + iptables -w -S ACCOUNTING_BLOCK > /tmp/iptables.block.$$ + if [ "$enable" = 1 ] + then + # insert the block rule + check=$(cat /tmp/iptables.block.$$ | grep -e "-m comment --comment internet_block -j DROP") + if [ -z "$check" ] + then + iptables -w -I ACCOUNTING_BLOCK -m comment --comment internet_block -j DROP 2>/dev/null + fi + else + # remove the block rule + count=$(cat /tmp/iptables.block.$$ | grep -e "-m comment --comment internet_block -j DROP" | wc -l) + for i in $(seq 1 $count) + do + iptables -w -D ACCOUNTING_BLOCK -m comment --comment internet_block -j DROP 2>/dev/null + done + fi + + rm -rf /tmp/iptables.block.$$ +} + +internet_block $1 + diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/change.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/change.sh new file mode 100644 index 0000000..003fec7 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/change.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +log() { + logger -t "wrtbwmon" "$@" +} + +enable=$1 + +WX=$(uci -q get custom.bwallocate.lock) +if [ "$WX" = "1" ]; then + enable="1" +fi +uci set bwmon.general.enabled=$enable +uci commit bwmon diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/chksms.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/chksms.sh new file mode 100644 index 0000000..20b3376 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/chksms.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +CURRMODEM=1 + +rm -f /tmp/texting +CPORT=$(uci -q get modem.modem$CURRMODEM.commport) +if [ -z $CPORT ]; then + return +fi +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "smschk.gcom" "$CURRMODEM") +ERROR="ERROR" +if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` +then + return +fi +echo "0" > /tmp/texting +uci set modem.general.smsnum='1' +uci commit modem \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/cleanup.lua b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/cleanup.lua new file mode 100644 index 0000000..2c5d764 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/cleanup.lua @@ -0,0 +1,32 @@ +#!/usr/bin/lua + +filepost = "-mac_data.js" +dirname = '/usr/lib/bwmon/data' + +function clean() + nummon = 0 + months = {} + f = io.popen('/bin/ls ' .. dirname) + for name in f:lines() do + s, e = name:find(filepost) + if s ~= nil then + nummon = nummon + 1 + months[nummon] = dirname .. "/" .. name + end + end + f:close() + + count = 1 + if nummon > 0 then + for i=nummon,1,-1 do + if count > 3 then + os.execute("rm -f " .. months[i]) + end + count = count + 1 + end + end +end + +clean() +dirname = '/tmp/bwmon/data' +clean() \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/create.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/create.sh new file mode 100644 index 0000000..348d873 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/create.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +log() { + logger -t "createdata" "$@" +} + +lua /usr/lib/bwmon/create_data.lua +sleep 60 +while [ true ] +do + result=`ps | grep -i "create_data.lua" | grep -v "grep" | wc -l` + if [ $result -lt 1 ]; then + lua /usr/lib/bwmon/create_data.lua + fi + sleep 60 +done \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/create_data.lua b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/create_data.lua new file mode 100644 index 0000000..fc3fba8 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/create_data.lua @@ -0,0 +1,193 @@ +#!/usr/bin/lua + +dirname = '/tmp/bwmon/data' +filepost = "-mac_data.js.bk" +bw = {} +maclist = {} +devices = {} +totaldevices = 0 +totaldown = 0 +totalup = 0 +total = 0 + +printf = function(s,...) + local ss = s:format(...) + os.execute("/usr/lib/rooter/logprint.sh " .. ss) +end + +function ltrim(s) + return s:match'^%s*(.*)' +end + +function calc(total) + if total < 1000 then + tstr = string.format("%.2f", total) + tfm = " K" + else + if total < 1000000 then + tstr = string.format("%.2f", total/1000) + tfm = " MB" + else + tstr = string.format("%.2f", total/1000000) + tfm = " GB" + end + end + str = tstr .. tfm + return ltrim(str) +end + +function monthly(datafile) + file = io.open(datafile, "r") + i = 0 + dayx = 0 + repeat + line = file:read("*line") + if line == nil then + break + end + s, e = line:find("start day") + if s ~= nil then + dayx = dayx + 1 + repeat + line = file:read("*line") + s, e = line:find("end day") + if s ~= nil then + break + end + s, e = line:find("\"mac\":\"") + bs, be = line:find("\"", e+1) + mac = line:sub(e+1, bs-1) + if bw[mac] == nil then + maclist[i] = mac + i = i + 1 + bw[mac] = {} + bw[mac]['down'] = 0 + bw[mac]['offdown'] = 0 + bw[mac]['up'] = 0 + bw[mac]['offup'] = 0 + end + s, e = line:find("\"down\":\"") + bs, be = line:find("\"", e+1) + down = tonumber(line:sub(e+1, bs-1)) + bw[mac]['down'] = bw[mac]['down'] + down + s, e = line:find("\"up\":\"") + bs, be = line:find("\"", e+1) + up = tonumber(line:sub(e+1, bs-1)) + bw[mac]['up'] = bw[mac]['up'] + up + s, e = line:find("\"offdown\":\"") + bs, be = line:find("\"", e+1) + offdown = tonumber(line:sub(e+1, bs-1)) + bw[mac]['offdown'] = bw[mac]['offdown'] + offdown + s, e = line:find("\"offup\":\"") + bs, be = line:find("\"", e+1) + offup = tonumber(line:sub(e+1, bs-1)) + bw[mac]['offup'] = bw[mac]['offup'] + offup + s, e = line:find("\"ip\":\"") + bs, be = line:find("\"", e+1) + bw[mac]['ip'] = line:sub(e+1, bs-1) + s, e = line:find("\"name\":\"") + bs, be = line:find("\"", e+1) + bw[mac]['name'] = line:sub(e+1, bs-1) + until 1==0 + end + until 1==0 + file:close() + return dayx +end + +function totals(bw, maclist, dayz) + totaldown = 0 + totalup = 0 + utotaldown = 0 + utotalup = 0 + j=0 + while maclist[j] ~= nil do + totaldown = totaldown + bw[maclist[j]]['down'] + totalup = totalup + bw[maclist[j]]['up'] + utotaldown = utotaldown + bw[maclist[j]]['offdown'] + utotalup = utotalup + bw[maclist[j]]['offup'] + j = j + 1 + end + total = totalup + totaldown + ptotal = (total / dayz) * 30 +end + +function showdevices(bw, maclist) + k = 0 + while maclist[k] ~= nil do + k = k + 1 + end + if k > 0 then + j = 0 + while maclist[j] ~= nil do + dtot = bw[maclist[j]]['down'] + bw[maclist[j]]['up'] + devices[j] = bw[maclist[j]]['ip'] .."|" .. maclist[j] + devices[j] = devices[j] .. "|" .. calc(bw[maclist[j]]['down']) .. "|" .. calc(bw[maclist[j]]['up']) + devices[j] = devices[j] .. "|" .. calc(dtot) .. "|" .. bw[maclist[j]]['name'] + j = j + 1 + end + end + totaldevices = j +end + +os.execute("echo 0 > /tmp/lockbw") +dataname = nil +f = io.popen('/bin/ls ' .. dirname) +for name in f:lines() do + s, e = name:find(filepost) + if s ~= nil then + dataname = dirname .. "/" .. name + end +end +f:close() + +if dataname ~= nil then + days = monthly(dataname) + totals(bw, maclist, days) + tfile = io.open("/tmp/bwdata", "w") + tfile:write(days, "\n") + tfile:write(tostring(total), "\n") + tfile:write(calc(total), "\n") + tfile:write(tostring(totaldown), "\n") + tfile:write(calc(totaldown), "\n") + tfile:write(tostring(totalup), "\n") + tfile:write(calc(totalup), "\n") + tfile:write(tostring(ptotal), "\n") + tfile:write(calc(ptotal), "\n") + -- + -- allocated bandwidth in K + -- + bwallo='rm -f /tmp/bwallo; x=$(uci -q get custom.bwallocate.allocate); echo $x >> /tmp/bwallo; x=$(uci -q get custom.bwallocate.password); echo $x >> /tmp/bwallo' + os.execute(bwallo) + file = io.open("/tmp/bwallo", "r") + if file == nil then + allo = 1000000000 + passw = "password" + else + allos = file:read("*line") + allo = tonumber(allos) * 1000000 + passw = file:read("*line") + file:close() + end + tfile:write(tostring(allo), "\n") + tfile:write(calc(allo), "\n") + tfile:write(passw, "\n") + + showdevices(bw, maclist) + tfile:write(tostring(totaldevices), "\n") + if totaldevices > 0 then + for i=0, totaldevices-1 do + tfile:write(devices[i], "\n") + end + end + tfile:close() +else + tfile = io.open("/tmp/bwdata", "w") + tfile:write("0\n") + tfile:write("0\n") + tfile:close() +end +os.execute("rm -f /tmp/lockbw") +os.execute("/usr/lib/bwmon/excede.sh " .. tostring(total) .. " " .. tostring(allo) .. " " .. tostring(ptotal)) +os.execute("/usr/lib/bwmon/savetot.sh \"" .. calc(total) .. "\"") +os.execute("/usr/lib/bwmon/perday.lua") diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/data/placeholder b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/data/placeholder new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/data/placeholder @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/datainc.lua b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/datainc.lua new file mode 100644 index 0000000..6ef57c4 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/datainc.lua @@ -0,0 +1,21 @@ +#!/usr/bin/lua + +prev = arg[1] -- previous increment in GB +incr = arg[2] -- fixed increment in GB +used = arg[3] -- amt used in Kb + +used = used / 1000000 -- used in GB +current = prev + incr +running = "0" +if used >= current then + while used >= (current + incr) do + current = current + incr + end + prev = current + running = "1" +end + +tfile = io.open("/tmp/bwinc", "w") +tfile:write("prev=\"", prev, "\"\n") +tfile:write("runn=\"", running, "\"") +tfile:close() \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/dataper.lua b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/dataper.lua new file mode 100644 index 0000000..d5d0527 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/dataper.lua @@ -0,0 +1,16 @@ +#!/usr/bin/lua + +alloc = arg[1] -- allocate increment in GB +per = arg[2] -- fixed percentage in GB +used = arg[3] -- amt used in Kb + +used = used / 10000 -- used in GB +percent = used / alloc +running = "0" +if percent >= per then + running = "1" +end + +tfile = io.open("/tmp/bwper", "w") +tfile:write("runn=\"", running, "\"") +tfile:close() \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/dotext.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/dotext.sh new file mode 100644 index 0000000..651c410 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/dotext.sh @@ -0,0 +1,82 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "TEXTING" "$@" +} + +getbw() { + alloc=$(uci -q get custom.bwallocate.allocate)"000000" + if [ -e /tmp/bwdata ]; then + while IFS= read -r line; do + days=$line + if [ $days = '0' ]; then + used="0" + return + fi + read -r line + used=$line + read -r line + useda=$line + return + done < /tmp/bwdata + else + used="0" + useda="0.00 K" + fi +} + +sendmsg() { + getbw + /usr/lib/bwmon/amtleft.lua $alloc $used + bwleft=$(cat /tmp/amtleft) + + #ident=$(uci -q get custom.texting.ident) + ident=$(uci -q get modem.modem1.iccid) + if [ -z "$ident" ]; then + ident="Unknown User" + fi + message="$ident has used $useda bandwidth and has $bwleft of bandwidth left" + + tore=$(uci -q get custom.texting.tore) + if [ $tore = '0' ]; then + phone=$(uci -q get custom.texting.phone) + /usr/lib/bwmon/chksms.sh + if [ -e /tmp/texting ]; then + /usr/lib/sms/smsout.sh "$phone" "$message" + log "$phone $message" + else + log "$message not sent. No SMS." + fi + else + email=$(uci -q get custom.texting.email) + + host=$(uci -q get custom.texting.smtp) + user=$(uci -q get custom.texting.euser) + pass=$(uci -q get custom.texting.epass) + + STEMP="/tmp/eemail" + MSG="/usr/lib/bwmon/msmtprc" + DST="/etc/msmtprc" + rm -f $STEMP + cp $MSG $STEMP + sed -i -e "s!#HOST#!$host!g" $STEMP + sed -i -e "s!#USER#!$user!g" $STEMP + sed -i -e "s!#PASS#!$pass!g" $STEMP + mv $STEMP $DST + + STEMP="/tmp/emailmsg" + MSG="/usr/lib/bwmon/message" + rm -f $STEMP + cp $MSG $STEMP + sed -i -e "s!#EMAIL#!$email!g" $STEMP + sed -i -e "s!#MESSAGE#!$message!g" $STEMP + sed -i -e "s!#IDENT#!$ident!g" $STEMP + mess=$(cat /tmp/emailmsg) + echo -e "$mess" | msmtp --read-envelope-from --read-recipients + log "$email $message" + fi + +} + +sendmsg \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/editemail.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/editemail.sh new file mode 100644 index 0000000..61c4ec3 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/editemail.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +log() { + logger -t "edit email" "$@" +} + +host=$(uci -q get custom.texting.smtp) +if [ -z $host ]; then + exit 0 +fi +user=$(uci -q get custom.texting.euser) +if [ -z $user ]; then + exit 0 +fi +pass=$(uci -q get custom.texting.epass) +if [ -z $pass ]; then + exit 0 +fi + +STEMP="/tmp/eemail" +MSG="/usr/lib/bwmon/msmtprc" +DST="/etc/msmtprc" +rm -f $STEMP +cp $MSG $STEMP +sed -i -e "s!#HOST#!$host!g" $STEMP +sed -i -e "s!#USER#!$user!g" $STEMP +sed -i -e "s!#PASS#!$pass!g" $STEMP +mv $STEMP $DST + \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/excede.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/excede.sh new file mode 100644 index 0000000..5c9af09 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/excede.sh @@ -0,0 +1,94 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "excede BW " "$@" +} + +do_throttle() { + local config=$1 + local limit + + config_get name $1 name + config_get limit $1 limit + config_get throttle $1 throttle + let kamt=limit*1000000 + if [ $amt -gt $kamt ]; then + if [ $limit -gt $baselimit ]; then + speed=$throttle + level=$name + baselimit=$limit + fi + fi +} + +lock=$(uci -q get custom.bwallocate.lock) +if [ $lock = "1" ]; then + enb=$(uci -q get custom.bwallocate.enabled) + if [ $enb = '1' ]; then + allocate=$2 + total=$1 + /usr/lib/bwmon/block 0 + action=$(uci -q get custom.bwallocate.action) + if [ -z $action ]; then + action=0 + fi + if [ ! -e /usr/lib/throttle/throttle.sh ]; then + action=0 + fi + if [ $action != "2" ]; then + if [ $total -gt $allocate ]; then + if [ $action = "0" ]; then + if [ -e /etc/nodogsplash/control ]; then + /etc/nodogsplash/control block + else + /usr/lib/bwmon/block 1 + fi + else + down=$(uci -q get custom.bwallocate.down) + if [ -z $down ]; then + down=5 + fi + up=$(uci -q get custom.bwallocate.up) + if [ -z $up ]; then + up=2 + fi + /usr/lib/throttle/throttle.sh start $down $up + fi + else + if [ -e /usr/lib/throttle/throttle.sh ]; then + /usr/lib/throttle/throttle.sh stop + fi + if [ -e /etc/nodogsplash/control ]; then + /etc/nodogsplash/control unblock + fi + /usr/lib/bwmon/block 0 + fi + else + meth=$(uci -q get custom.bwallocate.meth) + if [ -z $meth ]; then + meth="0" + fi + if [ $meth = "0" ]; then + amt=$total + else + amt=$3 + fi + speed="0" + baselimit="0" + config_load custom + config_foreach do_throttle throttle + if [ $speed != "0" ]; then + /usr/lib/bwmon/float.lua "$speed" + source /tmp/float + /usr/lib/throttle/throttle.sh start $SPEED $SPEED 1 + log "Throttled to $speed Mbps" + else + if [ -e /usr/lib/throttle/throttle.sh ]; then + /usr/lib/throttle/throttle.sh stop + fi + fi + + fi + fi +fi \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/external.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/external.sh new file mode 100644 index 0000000..9b11296 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/external.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +log() { + logger -t "wrtbwmon" "$@" +} + +external=$1 + +ext=$(uci -q get bwmon.general.external) + +if [ "$ext" = "$external" ]; then + exit 0 +else + uci set bwmon.general.external=$external + uci commit bwmon + PID=$(ps |grep "wrtbwmon.sh" | grep -v grep |head -n 1 | awk '{print $1}') + PID1=$(ps |grep "create.sh" | grep -v grep |head -n 1 | awk '{print $1}') + if [ ! -z "$PID" ]; then + kill -9 $PID + kill -9 $PID1 + fi + /usr/lib/bwmon/wrtbwmon.sh & + /usr/lib/bwmon/create.sh & +fi \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/float.lua b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/float.lua new file mode 100644 index 0000000..4c40f3e --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/float.lua @@ -0,0 +1,9 @@ +#!/usr/bin/lua + +val = arg[1] + +retval = val * 1000 + +local tfile = io.open("/tmp/float", "w") +tfile:write("SPEED=\"", retval, "\"") +tfile:close() \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/message b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/message new file mode 100644 index 0000000..509a0e4 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/message @@ -0,0 +1,4 @@ +From: Broadband Usage +To: #EMAIL# +Subject: Broadband Usage +#MESSAGE# diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/msmtprc b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/msmtprc new file mode 100644 index 0000000..4b8a3f8 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/msmtprc @@ -0,0 +1,12 @@ +account default +host #HOST# +port 587 +auto_from off +from #USER# +aliases /etc/aliases +tls on +tls_starttls on +tls_trust_file /etc/ssl/certs/ca-certificates.crt +auth on +user #USER# +password #PASS# \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/perday.lua b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/perday.lua new file mode 100644 index 0000000..1f133ef --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/perday.lua @@ -0,0 +1,204 @@ +#!/usr/bin/lua + +function ltrim(s) + return s:match'^%s*(.*)' +end + +function calc(total) + if total < 1000 then + tstr = string.format("%.2f", total) + tfm = " K" + else + if total < 1000000 then + tstr = string.format("%.2f", total/1000) + tfm = " MB" + else + tstr = string.format("%.2f", total/1000000) + tfm = " GB" + end + end + str = tstr .. tfm + return ltrim(str) +end + +local function bubblesort(a) + repeat + local swapped = false + for i = 1, table.getn(a) do + if a[i - 1] < a[i] then + a[i], a[i - 1] = a[i - 1], a[i] + swapped = true + end -- if + end -- for + until swapped == false +end + +function ConBytes(line) + local s, e, bs, be + s, e = line:find(" ") + bs, be = line:find("K", e+1) + if bs == nil then + bs, be = line:find("MB", e+1) + if bs == nil then + val = tonumber(line:sub(1, e-1)) * 1000000 + else + val = tonumber(line:sub(1, e-1)) * 1000 + end + else + val = tonumber(line:sub(1, e-1)) + end + return val +end + +dirname = '/usr/lib/bwmon/data' +filepost = "-mac_data.js" +monthly = dirname .. "/monthly.data" +daylist = {} +dayline = {} +monlist = {} +monline = {} + +dataname = nil +f = io.popen('/bin/ls ' .. dirname) +for name in f:lines() do + s, e = name:find(filepost) + if s ~= nil then + dataname = name + end +end +f:close() + +if dataname ~= nil then + yearmon = dataname:sub(1, 7) + datafile = dirname .. "/" .. dataname + file = io.open(datafile, "r") + i = 0 + repeat + line = file:read("*line") + if line == nil then + break + end + s, e = line:find("start day") + if s ~= nil then + day = line:sub(e+1) + nday = tonumber(day) + day= tostring(nday) + if nday < 10 then + day = "0" .. day + end + yearmonday = yearmon .. "-" .. day + + daydwn = 0 + dayup = 0 + repeat + line = file:read("*line") + s, e = line:find("end day") + if s ~= nil then + dayt = dayup + daydwn + if dayt > 0 then + daylist[i] = yearmonday + i = i + 1 + dayline[yearmonday] = {} + dayline[yearmonday]['down'] = daydwn + dayline[yearmonday]['up'] = dayup + dayline[yearmonday]['total'] = dayup + daydwn + end + break + end + s, e = line:find("\"down\":\"") + bs, be = line:find("\"", e+1) + daydwn = daydwn + tonumber(line:sub(e+1, bs-1)) + s, e = line:find("\"up\":\"") + bs, be = line:find("\"", e+1) + dayup = dayup + tonumber(line:sub(e+1, bs-1)) + until 1==0 + end + until 1==0 + + if i > 0 then + tfile = io.open(monthly, "r") + if tfile == nil then + for j = 0,i-1 + do + lin = daylist[j] + monlist[j] = lin + monline[lin] = {} + dwn = calc(dayline[lin]['down']) + up = calc(dayline[lin]['up']) + total = calc(dayline[lin]['total']) + dataline = lin .. "|" .. dwn .. "|" .. up .. "|" .. total + monline[lin]['data'] = dataline + end + k = i + else + k = 0 + ksize = tfile:read("*line") + kdwn = tfile:read("*line") + kup = tfile:read("*line") + ktotal = tfile:read("*line") + repeat + line = tfile:read("*line") + if line == nil then + break + end + ymd = line:sub(1,10) + monlist[k] = ymd + k = k + 1 + monline[ymd] = {} + monline[ymd]['data'] = line + until 1==0 + tfile:close() + + for j = 0,i-1 + do + lin = daylist[j] + if monline[lin] == nil then + monlist[k] = lin + k = k + 1 + monline[lin] = {} + end + dwn = calc(dayline[lin]['down']) + up = calc(dayline[lin]['up']) + total = calc(dayline[lin]['total']) + dataline = lin .. "|" .. dwn .. "|" .. up .. "|" .. total + monline[lin]['data'] = dataline + end + end + + bubblesort(monlist) + + tfile = io.open(monthly, "w") + if k > 30 then + k = 30 + end + tfile:write(tostring(k), "\n") + fdown = 0 + fup = 0 + ftotal = 0 + for j = 0,k-1 + do + lin = monlist[j] + dataline = monline[lin]['data'] + s, e = dataline:find("|") + if s ~= nil then + bs, be = dataline:find("|", e+1) + fdown = ConBytes(dataline:sub(e+1, be-1)) + fdown + s, e = dataline:find("|", be+1) + fup = ConBytes(dataline:sub(be+1, e-1)) + fup + ftotal = ConBytes(dataline:sub(e+1)) + ftotal + end + end + tfile:write(calc(fdown), "\n") + tfile:write(calc(fup), "\n") + tfile:write(calc(ftotal), "\n") + for j = 0,k-1 + do + lin = monlist[j] + dataline = monline[lin]['data'] + tfile:write(dataline, "\n") + end + tfile:close() + end + + file:close() +end \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/process.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/process.sh new file mode 100644 index 0000000..42e38b6 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/process.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +log() { + logger -t "BWmon Process" "$@" +} + +running=0 +if [ -e "/tmp/WRTbmon" ]; then + running=1 +fi + +sleep 5 + +if [ $running = 0 ]; then + log "Enable BandWidthMonitor" + /usr/lib/bwmon/wrtbwmon.sh & +fi + + + diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/rollover.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/rollover.sh new file mode 100644 index 0000000..648b9d6 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/rollover.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +log() { + logger -t "Rollover" "$@" +} + +amount=$1 + +uci set custom.bwallocate.rollover=$amount +uci set custom.bwallocate.persent="0" +uci commit custom diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/savetot.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/savetot.sh new file mode 100644 index 0000000..1a780ba --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/savetot.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +log() { + logger -t "save total" "$@" +} + +total=$1 + +uci set custom.bwday.bwday="$total" +uci commit custom \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/sendsms.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/sendsms.sh new file mode 100644 index 0000000..3fc4ff4 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/sendsms.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +log() { + logger -t "sendsms" "$@" +} + +chksms() { + CURRMODEM=1 + rm -f /tmp/texting + CPORT=$(uci -q get modem.modem$CURRMODEM.commport) + if [ -z $CPORT ]; then + return + fi + SMS_OK=$(uci -q get modem.modem$CURRMODEM.sms) + if [ "$SMS_OK" != "1" ]; then + return + fi + echo "0" > /tmp/texting +} + +delay=$(uci -q get modem.modeminfo$CURRMODEM.delay) +if [ "$delay" -gt 0 ]; then + cnt=1 + while true; do + sleep 3600 + let cnt=cnt+1 + if [ $cnt -gt $delay ]; then + break + fi + done +fi +total=$(uci -q get.custom.bwday.bwday) +chksms +phone=$(uci -q get modem.modeminfo$CURRMODEM.bwphone) +if [ (! -z "$phone") -o ("$phone" != "0") ]; then + if [ -e /tmp/texting ]; then + /usr/lib/sms/smsout.sh "$phone" "$total" + fi +fi diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/textbw.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/textbw.sh new file mode 100644 index 0000000..5d9d589 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/textbw.sh @@ -0,0 +1,153 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "TEXTING" "$@" +} + +checktime() { + SHOUR=$(uci -q get custom.texting.time) + EHOUR=`expr $SHOUR + 1` + if [ $EHOUR -gt 95 ]; then + EHOUR=0 + fi + HOUR=`expr $SHOUR / 4` + let "TH = $HOUR * 4" + let "TMP1 = $SHOUR - $TH" + let "MIN = $TMP1 * 15" + shour=$HOUR + smin=$MIN + + HOUR=`expr $EHOUR / 4` + let "TH = $HOUR * 4" + let "TMP1 = $EHOUR - $TH" + let "MIN = $TMP1 * 15" + ehour=$HOUR + emin=$MIN + + chour=$(date +%H) + cmin=$(date +%M) + if [ $shour -gt $chour ]; then + flag="0" + else + if [ $shour -eq $chour ]; then + if [ $smin -le $cmin ]; then + flag="1" + else + flag="0" + fi + else + flag="1" + fi + fi + + if [ $flag = "1" ]; then + if [ $ehour -lt $chour ]; then + flag="0" + else + if [ $ehour -eq $chour ]; then + if [ $emin -lt $cmin ]; then + flag="0" + else + flag="1" + fi + else + flag="1" + fi + fi + fi + echo $flag +} + +getbw() { + alloc=$(uci -q get custom.bwallocate.allocate)"000000" + if [ -e /tmp/bwdata ]; then + while IFS= read -r line; do + days=$line + if [ $days = '0' ]; then + used="0" + return + fi + read -r line + used=$line + return + done < /tmp/bwdata + else + used="0" + fi +} + +checkamt() { + istime=$(checktime) + if [ $istime = '1' ]; then + incr=$(uci -q get custom.texting.increment) + getbw + /usr/lib/bwmon/datainc.lua $prev $incr $used + source /tmp/bwinc + uci set custom.texting.used=$prev + uci commit custom + echo $runn + else + echo "0" + fi +} + +checkper() { + istime=$(checktime) + if [ $istime = '1' ]; then + prev=$(uci -q get custom.texting.used) + per=$(uci -q get custom.bwallocate.percent) + persent=$(uci -q get custom.bwallocate.persent) + if [ "$persent" != "1" ]; then + getbw + /usr/lib/bwmon/dataper.lua $alloc $per $used + source /tmp/bwper + if [ $runn = "1" ]; then + uci set custom.bwallocate.persent="1" + uci commit custom + fi + echo $runn + else + echo "0" + fi + else + echo "0" + fi +} + +delay=900 +while true +do + EN=$(uci -q get custom.bwallocate.enabled) + if [ $EN = "1" ]; then + MT=$(uci -q get custom.texting.method) + if [ $MT = '0' ]; then + days=$(uci -q get custom.texting.days) + daysdate=$( date +%d ) + daysdate="${daysdate#"${daysdate%%[!0]*}"}" + remain=$((daysdate % days)) + if [ $remain -eq 0 ]; then + running=$(checktime) + else + running="0" + fi + else + if [ $MT = '1' ]; then + running=$(checkamt) + else + running=$(checkper) + fi + fi + if [ $running = "1" ]; then + EN=$(uci -q get custom.texting.text) + if [ $EN = "1" ]; then + /usr/lib/bwmon/dotext.sh + sleep $delay + fi + else + sleep $delay + fi + else + sleep $delay + fi +done \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/wrtbwmon.sh b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/wrtbwmon.sh new file mode 100644 index 0000000..55e3924 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/bwmon/wrtbwmon.sh @@ -0,0 +1,508 @@ +#!/bin/sh + +setbackup() { + extn=$(uci -q get bwmon.general.external) + if [ "$extn" = "0" ]; then + backPath=/usr/lib/bwmon/data/ + else + if [ -e "$extn""/" ]; then + backPath=$extn"/data/" + else + backPath=/usr/lib/bwmon/data/ + uci set bwmon.general.external="0" + uci commit bwmon + fi + fi + if [ ! -e "$backpath" ]; then + mkdir -p $backPath + fi +} + +LAN_TYPE=$(uci get network.lan.ipaddr | awk -F. ' { print $1"."$2 }') +LEASES_FILE=/tmp/dhcp.leases +lockDir=/tmp/WRTbmon + +ifname="ifname" +source /etc/openwrt_release +twone=$(echo "$DISTRIB_RELEASE" | grep "21.02") +if [ ! -z "$twone" ]; then + ifname="device" +fi + + +[ ! -d "$lockDir" ] && mkdir "$lockDir" +basePath="/tmp/bwmon/" +mkdir -p $basePath"data" +dataPath=$basePath"data/" +setbackup +lockDir1=/tmp/wrtbwmon1.lock +lockDir=/tmp/wrtbwmon.lock +mkdir -p "$lockDir" +pidFile=$lockDir/pid +STARTIMEX=$(date +%s) +STARTIMEY=$(date +%s) +STARTIMEZ=$(date +%s) +cYear=$(date +%Y) +cDay=$(date +%d) +cMonth=$(date +%m) +setup_time=60 +update_time=60 +bs=$(uci -q get bwmon.general.backup) +let "bs=$bs*60" +backup_time=$bs +pause=30 +unlimited="peak" + +networkFuncs=/lib/functions/network.sh +uci=`which uci 2>/dev/null` +nslookup=`which nslookup 2>/dev/null` +nvram=`which nvram 2>/dev/null` +binDir=/usr/sbin +chains='INPUT OUTPUT FORWARD' +DEBUG= +interfaces='eth0' # in addition to detected WAN +DB="/tmp/usage.db" +mode= + +log() { + logger -t "wrtbwmon" "$@" +} + +header="#mac,ip,iface,in,out,total,first_date,last_date" + +createDbIfMissing() +{ + [ ! -f "$DB" ] && rm -f $DB;echo $header > "$DB" +} + +checkWAN() +{ + [ -z "$wan" ] && return +} + +lookup() +{ + MAC=$1 + IP=$2 + userDB=$3 + for USERSFILE in $userDB /tmp/dhcp.leases /tmp/dnsmasq.conf /etc/dnsmasq.conf /etc/hosts; do + [ -e "$USERSFILE" ] || continue + case $USERSFILE in + /tmp/dhcp.leases ) + USER=$(grep -i "$MAC" $USERSFILE | cut -f4 -s -d' ') + ;; + /etc/hosts ) + USER=$(grep "^$IP " $USERSFILE | cut -f2 -s -d' ') + ;; + * ) + USER=$(grep -i "$MAC" "$USERSFILE" | cut -f2 -s -d,) + ;; + esac + [ "$USER" = "*" ] && USER= + [ -n "$USER" ] && break + done + if [ -n "$DO_RDNS" -a -z "$USER" -a "$IP" != "NA" -a -n "$nslookup" ]; then + USER=`$nslookup $IP $DNS | awk '!/server can/{if($4){print $4; exit}}' | sed -re 's/[.]$//'` + fi + [ -z "$USER" ] && USER=${MAC} + echo $USER +} + +detectIF() +{ + if [ -f "$networkFuncs" ]; then + IF=`. $networkFuncs; network_get_device netdev $1; echo $netdev` + [ -n "$IF" ] && echo $IF && return + fi + + if [ -n "$uci" -a -x "$uci" ]; then + IF=`$uci get network.${1}.$ifname 2>/dev/null` + [ $? -eq 0 -a -n "$IF" ] && echo $IF && return + fi + + if [ -n "$nvram" -a -x "$nvram" ]; then + IF=`$nvram get ${1}_$ifname 2>/dev/null` + [ $? -eq 0 -a -n "$IF" ] && echo $IF && return + fi +} + +detectLAN() +{ + [ -e /sys/class/net/br-lan ] && echo br-lan && return + lan=$(detectIF lan) + [ -n "$lan" ] && echo $lan && return +} + +detectWAN() +{ + [ -n "$WAN_IF" ] && echo $WAN_IF && return + wan=$(detectIF wan) + [ -n "$wan" ] && echo $wan && return + wan=$(ip route show 2>/dev/null | grep default | sed -re '/^default/ s/default.*dev +([^ ]+).*/\1/') + [ -n "$wan" ] && echo $wan && return + [ -f "$networkFuncs" ] && wan=$(. $networkFuncs; network_find_wan wan; echo $wan) + [ -n "$wan" ] && echo $wan && return +} + +lock() +{ + attempts=0 + while [ $attempts -lt 10 ]; do + mkdir $lockDir1 2>/dev/null && break + attempts=$((attempts+1)) + pid=`cat $pidFile 2>/dev/null` + if [ -n "$pid" ]; then + if [ -d "/proc/$pid" ]; then + [ -n "$DEBUG" ] && echo "WARNING: Lockfile detected but process $(cat $pidFile) does not exist !" + rm -rf $lockDir1 + else + sleep 1 + fi + fi + done + mkdir $lockDir1 2>/dev/null + echo $$ > $pidFile + [ -n "$DEBUG" ] && echo $$ "got lock after $attempts attempts" + trap '' INT +} + +unlock() +{ + rm -rf $lockDir1 + [ -n "$DEBUG" ] && echo $$ "released lock" + trap "rm -f /tmp/*_$$.tmp; kill $$" INT +} + +# chain +newChain() +{ + chain=$1 + # Create the RRDIPT_$chain chain (it doesn't matter if it already exists). + iptables -t mangle -N RRDIPT_$chain 2> /dev/null + + # Add the RRDIPT_$chain CHAIN to the $chain chain if not present + iptables -t mangle -C $chain -j RRDIPT_$chain 2>/dev/null + if [ $? -ne 0 ]; then + [ -n "$DEBUG" ] && echo "DEBUG: iptables chain misplaced, recreating it..." + iptables -t mangle -I $chain -j RRDIPT_$chain + fi +} + +# chain tun +newRuleIF() +{ + chain=$1 + IF=$2 + + #!@todo test + if [ "$chain" = "OUTPUT" ]; then + cmd="iptables -t mangle -o $IF -j RETURN" + eval $cmd " -C RRDIPT_$chain 2>/dev/null" || eval $cmd " -A RRDIPT_$chain" + elif [ "$chain" = "INPUT" ]; then + cmd="iptables -t mangle -i $IF -j RETURN" + eval $cmd " -C RRDIPT_$chain 2>/dev/null" || eval $cmd " -A RRDIPT_$chain" + fi +} + +accounting(){ + LAN_IFACE="br-lan" + WAN_IFACE=$1 + LAN_IP=$(uci -q get network.lan.ipaddr) + SERVER_IP=$(echo $LAN_IP | cut -d . -f 1,2,3).0 + INTERNAL_NETMASK="$SERVER_IP/24" + + # create the ACCOUNTING chains + iptables -w -N ACCOUNTING_BLOCK 2> /dev/null + iptables -w -N ACCOUNTING_IN 2> /dev/null + iptables -w -N ACCOUNTING_OUT 2> /dev/null + check=0 + # check if accounting rule for ethernet wan not exist, add it + checks=$(iptables -w -L FORWARD -v -n | grep "ACCOUNTING" | grep "$WAN_IFACE") + [ -z "$checks" ] && check=1 + + # check if jumps to the ACCOUNTING chains are still at the start of the FORWARD chain + iptables -w -L FORWARD --line-numbers -n | grep "ACCOUNTING" | grep "^1 " + if [ $? -ne 0 -o "$check" = "1" ]; then + # remove old jump rules + iptables -w -D FORWARD $(iptables -w -L FORWARD --line-numbers | grep ACCOUNTING | grep -m 1 -o "[0-9]*") + while [ $? -eq 0 ]; do + iptables -w -D FORWARD $(iptables -w -L FORWARD --line-numbers | grep ACCOUNTING | grep -m 1 -o "[0-9]*") + done + # insert new jump rules at start of FORWARD chain + if [ -n "$WAN_IFACE" ] + then + iptables -w -I FORWARD -i ${WAN_IFACE} -j ACCOUNTING_IN + iptables -w -I FORWARD -o ${WAN_IFACE} -j ACCOUNTING_OUT + fi + iptables -w -I FORWARD -j ACCOUNTING_BLOCK + fi + + #For each host in the ARP table + grep ${LAN_IFACE} /proc/net/arp | while read IP TYPE FLAGS MAC MASK IFACE + do + #Add iptables rules (if non existing). + iptables -w -nL ACCOUNTING_IN | grep "${IP} " > /dev/null + if [ $? -ne 0 ]; then + iptables -w -I ACCOUNTING_IN -d ${IP} -s ${INTERNAL_NETMASK} -j RETURN + iptables -w -I ACCOUNTING_IN -d ${IP} ! -s ${INTERNAL_NETMASK} -j RETURN + fi + + iptables -w -nL ACCOUNTING_OUT | grep "${IP} " > /dev/null + if [ $? -ne 0 ]; then + iptables -w -I ACCOUNTING_OUT -s ${IP} -d ${INTERNAL_NETMASK} -j RETURN + iptables -w -I ACCOUNTING_OUT -s ${IP} ! -d ${INTERNAL_NETMASK} -j RETURN + fi + done +} + +setup() +{ + for chain in $chains; do + newChain $chain + done + + wan=$(detectWAN) + checkWAN + wan1=$(detectIF wan1) + wan2=$(detectIF wan2) + C1=$(uci -q get modem.modem1.connected) + C2=$(uci -q get modem.modem2.connected)$C1 + if [ ! -z $C2 ]; then + interfaces="$wan1 $wan2" + WW=$(uci -q get bwmon.bwwan.wan) + if [ "$WW" = "1" ]; then + interfaces=$interfaces $wan" wwan" + fi + else + WW=$(uci -q get bwmon.bwwan.wan) + if [ "$WW" = "1" ]; then + interfaces="$wan wwan" + else + return + fi + fi + + # track local data + for chain in INPUT OUTPUT; do + for interface in $interfaces; do + [ -n "$interface" ] && [ -e "/sys/class/net/$interface" ] && newRuleIF $chain $interface + #if [ -e /etc/bwlock ]; then + accounting $interface + #fi + done + done + + # this will add rules for hosts in arp table + update $dailyUsageDB + + rm -f /tmp/*_$$.tmp +} + +update() +{ + createDbIfMissing + checkWAN + PERTOTAL=0 + + > /tmp/iptables_$$.tmp + lock + # only zero our own chains + for chain in $chains; do + iptables -nvxL RRDIPT_$chain -t mangle -Z >> /tmp/iptables_$$.tmp + done + # the iptables and readDB commands have to be separate. Otherwise, + # they will fight over iptables locks + awk -v mode="$mode" -v interfaces=\""$interfaces"\" -f $binDir/readDB.awk \ + $DB \ + /proc/net/arp \ + /tmp/iptables_$$.tmp + + while read L1 + do + MAC=$(echo ${L1} | cut -f1 -d, ) + if [ $MAC != "#mac" ]; then + MAC=$(echo ${L1} | cut -f1 -d, ) + IP=$(echo ${L1} | cut -f2 -d, ) + IN=$(echo ${L1} | cut -f4 -d, ) + IN=$((${IN}/1000)) + OUT=$(echo ${L1} | cut -f5 -d, ) + OUT=$((${OUT}/1000)) + TOTAL=$(echo ${L1} | cut -f6 -d, ) + TOTAL=$((${TOTAL}/1000)) + let PERTOTAL=PERTOTAL+TOTAL + if [ $TOTAL -gt 0 -a $IP != "NA" ]; then + for USERSFILE in /tmp/dhcp.leases /tmp/dnsmasq.conf /etc/dnsmasq.conf /etc/hosts; do + [ -e "$USERSFILE" ] || continue + case $USERSFILE in + /tmp/dhcp.leases ) + NAME=$(grep -i "$MAC" $USERSFILE | cut -f4 -s -d' ') + ;; + /etc/hosts ) + NAME=$(grep "^$IP " $USERSFILE | cut -f2 -s -d' ') + ;; + * ) + NAME=$(grep -i "$MAC" "$USERSFILE" | cut -f2 -s -d,) + ;; + esac + [ "$NAME" = "*" ] && NAME= + [ -n "$NAME" ] && break + done + if [ -z $NAME ]; then + NAME="*" + fi + + echo "\"mac\":\""${MAC}"\"","\"down\":\""${IN}"\"","\"up\":\""${OUT}"\"","\"offdown\":\""0"\"","\"offup\":\""0"\"","\"ip\":\""${IP}"\"","\"name\":\""${NAME}"\"" >> ${1} + fi + fi + done < $DB + if [ -e /usr/lib/bwmon/period.sh ]; then + /usr/lib/bwmon/period.sh "$PERTOTAL" + fi + unlock +} + + +createFiles() +{ + while [ -e /tmp/lockbw ]; do + sleep 1 + done + echo "0" > /tmp/lockbw + while [ ! -e $backPath*"mac_data.js" ]; do + valid=$(cat /var/state/dnsmasqsec) + st=$(echo "$valid" | grep "ntpd says time is valid") + if [ ! -z "$st" ]; then + break + fi + sleep 10 + done + dailyUsageDB="$dataPath$cYear-$cMonth-$cDay-daily_data.js" + dailyUsageBack="$backPath$cYear-$cMonth-$cDay-daily_data.js" + if [ ! -f $dailyUsageBack ]; then + rm -f $backPath*"daily_data.js" + touch $dailyUsageDB + touch $dailyUsageBack + else + cp -f $dailyUsageBack $dailyUsageDB + fi + monthlyUsageDB="$dataPath$cYear-$cMonth-mac_data.js" + monthlyUsageBack="$backPath$cYear-$cMonth-mac_data.js" + if [ -f $monthlyUsageBack ]; then + cp -f $monthlyUsageBack $monthlyUsageDB".bk" + sed "/start day $cDay/,/end day $cDay/d" $monthlyUsageDB".bk" > $monthlyUsageDB + cp -f $monthlyUsageBack $monthlyUsageDB".bk" + else + rm -f $backPath*"mac_data.js" + touch $monthlyUsageDB + touch $monthlyUsageBack + /usr/lib/bwmon/backup.sh "backup" $cDay $monthlyUsageDB $dailyUsageDB $monthlyUsageBack $dailyUsageBack + fi + rm -f /tmp/lockbw +} + +shutDown() +{ + while [ -e /tmplockbw ]; do + sleep 1 + done + echo "0" > /tmp/lockbw + /usr/lib/bwmon/backup.sh "backup" $cDay $monthlyUsageDB $dailyUsageDB $monthlyUsageBack $dailyUsageBack + lua /usr/lib/bwmon/cleanup.lua + rm -f /tmp/lockbw +} + +checkSetup() +{ + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEX + if [ $ELAPSE -gt $setup_time ]; then + STARTIMEX=$CURRTIME + setup + /usr/lib/bwmon/backup.sh "setup" $cDay $monthlyUsageDB $dailyUsageDB $monthlyUsageBack $dailyUsageBack + fi +} + +checkUpdate() +{ + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEY + if [ $ELAPSE -gt $update_time ]; then + STARTIMEY=$CURRTIME + update $dailyUsageDB $unlimited + fi +} + +checkBackup() +{ + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEZ + bs=$(uci -q get bwmon.general.backup) + let "bs=$bs*60" + backup_time=$bs + if [ $ELAPSE -gt $backup_time ]; then + STARTIMEZ=$CURRTIME + shutDown + fi +} + +checkTime() +{ + while [ -e /tmplockbw ]; do + sleep 1 + done + echo "0" > /tmp/lockbw + pDay=$(date +%d) + pYear=$(date +%Y) + pMonth=$(date +%m) + if [ "$cDay" -ne "$pDay" ]; then + /usr/lib/bwmon/backup.sh "daily" $cDay $monthlyUsageDB $dailyUsageDB $monthlyUsageBack $dailyUsageBack + + cDay=$pDay + cMonth=$pMonth + cYear=$pYear + monthlyUsageBack="$backPath$cYear-$cMonth-mac_data.js" + if [ ! -e $monthlyUsageBack ]; then + rm -f $backPath*"mac_data.js" + fi + rm -f $dataPath[[:digit:]][[:digit:]][[:digit:]][[:digit:]]"-"[[:digit:]][[:digit:]]"-"[[:digit:]][[:digit:]]-daily_data.js + rm -f $backPath[[:digit:]][[:digit:]][[:digit:]][[:digit:]]"-"[[:digit:]][[:digit:]]"-"[[:digit:]][[:digit:]]-daily_data.js + roll=$(uci -q get custom.bwallocate.rollover) + [ -z $roll ] && roll=1 + if [ "$roll" -eq "$pDay" ]; then + rm -f $monthlyUsageDB + rm -f $backPath*"mac_data.js" + monthlyUsageDB="$dataPath$cYear-$cMonth-mac_data.js" + monthlyUsageBack="$backPath$cYear-$cMonth-mac_data.js" + touch $monthlyUsageDB + uci set custom.texting.used='0' + uci commit custom + if [ -e /usr/lib/bwmon/periodreset.sh ]; then + /usr/lib/bwmon/periodreset.sh + fi + fi + rm -f $dailyUsageDB + rm -f $backPath*"daily_data.js" + dailyUsageDB="$dataPath$cYear-$cMonth-$cDay-daily_data.js" + touch $dailyUsageDB + dailyUsageBack="$backPath$cYear-$cMonth-$cDay-daily_data.js" + fi + rm -f /tmp/lockbw +} + +createFiles +setup +while [ -d $lockDir ]; do + checkSetup + checkTime + checkBackup + n=0 + while [ true ] ; do + n=$(($n + 1)) + if [ ! -d "$lockDir" ]; then + shutDown + exit 0 + fi + [ "$n" -gt "$pause" ] && break; + sleep 1 + done +done diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/lua/luci/controller/bwmon.lua b/rooter/0optionalapps/bwmon/files/usr/lib/lua/luci/controller/bwmon.lua new file mode 100644 index 0000000..ac269e8 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/lua/luci/controller/bwmon.lua @@ -0,0 +1,119 @@ +module("luci.controller.bwmon", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + entry({"admin", "nlbw"}, firstchild(), translate("Bandwidth Monitor"), 80).dependent=false + page = entry({"admin", "nlbw", "bwmon"}, template("bwmon/bwmon"), translate("ROOter Bandwidth Monitor"), 70) + page.dependent = true + + entry({"admin", "nlbw", "check_bw"}, call("action_check_bw")) + entry({"admin", "nlbw", "change_bw"}, call("action_change_bw")) + entry({"admin", "nlbw", "change_roll"}, call("action_change_roll")) + entry({"admin", "nlbw", "change_enable"}, call("action_change_enable")) + entry({"admin", "nlbw", "change_bwenable"}, call("action_change_bwenable")) + entry({"admin", "nlbw", "change_backup"}, call("action_change_backup")) + entry({"admin", "nlbw", "change_external"}, call("action_change_external")) + entry({"admin", "nlbw", "change_bwwan"}, call("action_change_bwwan")) +end + +function action_check_bw() + local rv = {} + local maclist = {} + + file = io.open("/tmp/bwdata", "r") + if file ~= nil then + rv['days'] = file:read("*line") + if rv['days'] ~= "0" then + rv['total'] = file:read("*line") + rv['ctotal'] = file:read("*line") + rv['totaldown'] = file:read("*line") + rv['ctotaldown'] = file:read("*line") + rv['totalup'] = file:read("*line") + rv['ctotalup'] = file:read("*line") + rv['ptotal'] = file:read("*line") + rv['cptotal'] = file:read("*line") + rv['atotal'] = file:read("*line") + rv['catotal'] = file:read("*line") + rv['password'] = file:read("*line") + j = file:read("*line") + if j == nil then + j = 0 + end + rv['macsize'] = j + if j ~=0 then + for i=0, j-1 do + maclist[i] = file:read("*line") + end + rv['maclist'] = maclist + end + end + file:close() + else + rv['days'] = 0 + end + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if multilock == "0" then + rv['lock'] = luci.model.uci.cursor():get("custom", "bwallocate", "lock") + else + if rootlock == "0" then + rv['lock'] = "1" + else + rv['lock'] = "0" + end + end + rv['rollover'] = luci.model.uci.cursor():get("custom", "bwallocate", "rollover") + rv['enabled'] = luci.model.uci.cursor():get("custom", "bwallocate", "enabled") + rv['bwenabled'] = luci.model.uci.cursor():get("bwmon", "general", "enabled") + rv['backup'] = luci.model.uci.cursor():get("bwmon", "general", "backup") + rv['external'] = luci.model.uci.cursor():get("bwmon", "general", "external") + rv['bwwan'] = luci.model.uci.cursor():get("bwmon", "bwwan", "wan") + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_change_bw() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/bwmon/allocate.sh " .. set) + +end + +function action_change_roll() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/bwmon/rollover.sh " .. set) + +end + +function action_change_enable() + local set = luci.http.formvalue("set") + os.execute("uci set custom.bwallocate.enabled=" .. set .. "; uci commit custom") + +end + +function action_change_bwenable() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/bwmon/change.sh " .. set) + +end + +function action_change_backup() + local set = luci.http.formvalue("set") + os.execute("uci set bwmon.general.backup=" .. set .. "; uci commit bwmon") + +end + +function action_change_external() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/bwmon/external.sh " .. set) + +end + +function action_change_bwwan() + local set = luci.http.formvalue("set") + os.execute("uci set bwmon.bwwan.wan=" .. set .. "; uci commit bwmon") + +end \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/lib/lua/luci/view/bwmon/bwmon.htm b/rooter/0optionalapps/bwmon/files/usr/lib/lua/luci/view/bwmon/bwmon.htm new file mode 100644 index 0000000..2664efd --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/lib/lua/luci/view/bwmon/bwmon.htm @@ -0,0 +1,610 @@ +<%+header%> +<% +local sys = require "luci.sys" +local utl = require "luci.util" +local fs = require "nixio.fs" + +function showicon(lck) + if lck == 0 then + return resource .. "/icons/unlock1.png" + else + return resource .. "/icons/lock1.png" + end +end + +-%> + + + + +
                +
                +

                <%:Bandwidth Monitor%>

                +
                +

                <%:Note : Bandwidth Monitor will not turn on until there is Internet Available%>

                + + + +
                + <%:Extra Internet Sources%> + + + + + + + + +
                <%:Include WAN and Hotspot%>
                +
                + +
                + <%:Data Backup Configuration%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                <%:Enable Data Backup%>
                <%:Backup Interval in Minutes%>
                +
                <%:Backup Storage Location%>
                + +
                + +
                + <%:Total Bandwidth%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                <%:Total Amount of Bandwidth used this Month : %>
                <%:Estimated Bandwidth to be used this Month : %>
                <%:Rollover Day : %>
                +
                + + + + + +
                + +
                + <%:Report%> + + + + + + + + + + + + + + + + + +
                <%:Number of Days in Reporting Period : %>
                <%:Total Amount of Download Bandwidth : %>
                <%:Total Amount of Upload Bandwidth : %>
                + + + + + + +
                + +
                + + + + + + + + + +
                <%:IP Address%>
                <%:Name%>
                <%:MAC Address%>
                <%:Bandwidth Down%>
                <%:Bandwidth Up%>
                <%:Bandwidth Total%>
                + + + +
                +
                + +
                +
                +<%+footer%> \ No newline at end of file diff --git a/rooter/0optionalapps/bwmon/files/usr/sbin/readDB.awk b/rooter/0optionalapps/bwmon/files/usr/sbin/readDB.awk new file mode 100644 index 0000000..cb57377 --- /dev/null +++ b/rooter/0optionalapps/bwmon/files/usr/sbin/readDB.awk @@ -0,0 +1,157 @@ +#!/usr/bin/awk + +function inInterfaces(host){ + return(interfaces ~ "(^| )"host"($| )") +} + +function newRule(arp_ip, + ipt_cmd){ + # checking for existing rules shouldn't be necessary if newRule is + # always called after db is read, arp table is read, and existing + # iptables rules are read. + ipt_cmd="iptables -t mangle -j RETURN -s " arp_ip + system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD") + ipt_cmd="iptables -t mangle -j RETURN -d " arp_ip + system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD") +} + +function total(i){ + return(bw[i "/in"] + bw[i "/out"]) +} + +function date( cmd, d){ + cmd="date +%d-%m-%Y_%H:%M:%S" + cmd | getline d + close(cmd) + #!@todo could start a process with "while true; do date ...; done" + return(d) +} + +BEGIN { + od="" + fid=1 + debug=0 + rrd=0 +} + +/^#/ { # get DB filename + FS="," + dbFile=FILENAME + next +} + +# data from database; first file +FNR==NR { #!@todo this doesn't help if the DB file is empty. + if($2 == "NA") + #!@todo could get interface IP here + n=$1 + else + n=$2 + + hosts[n] = "" # add this host/interface to hosts + mac[n] = $1 + ip[n] = $2 + inter[n] = $3 + bw[n "/in"] = $4 + bw[n "/out"] = $5 + firstDate[n] = $7 + lastDate[n] = $8 + next +} + +# not triggered on the first file +FNR==1 { + FS=" " + fid++ #!@todo use fid for all files; may be problematic for empty files + next +} + +# arp: ip hw flags hw_addr mask device +fid==2 { + #!@todo regex match IPs and MACs for sanity + arp_ip = $1 + arp_flags = $3 + arp_mac = $4 + arp_dev = $6 + if(arp_flags != "0x0" && !(arp_ip in ip)){ + if(debug) + print "new host:", arp_ip, arp_flags > "/dev/stderr" + hosts[arp_ip] = "" + mac[arp_ip] = arp_mac + ip[arp_ip] = arp_ip + inter[arp_ip] = arp_dev + bw[arp_ip "/in"] = bw[arp_ip "/out"] = 0 + firstDate[arp_ip] = lastDate[arp_ip] = date() + } + next +} + +#!@todo could use mangle chain totals or tailing "unnact" rules to +# account for data for new hosts from their first presence on the +# network to rule creation. The "unnact" rules would have to be +# maintained at the end of the list, and new rules would be inserted +# at the top. + +# skip line +# read the chain name and deal with the data accordingly +fid==3 && $1 == "Chain"{ + rrd=$2 ~ /RRDIPT_.*/ + next +} + +fid==3 && rrd && (NF < 9 || $1=="pkts"){ next } + +fid==3 && rrd { # iptables input + if($6 != "*"){ + m=$6 + n=m "/out" + } else if($7 != "*"){ + m=$7 + n=m "/in" + } else if($8 != "0.0.0.0/0"){ + m=$8 + n=m "/out" + } else { # $9 != "0.0.0.0/0" + m=$9 + n=m "/in" + } + + # remove host from array; any hosts left in array at END get new + # iptables rules + + #!@todo this deletes a host if any rule exists; if only one + # directional rule is removed, this will not remedy the situation + delete hosts[m] + + if($2 > 0){ # counted some bytes + if(mode == "diff" || mode == "noUpdate") + print n, $2 + if(mode!="noUpdate"){ + if(inInterfaces(m)){ # if label is an interface + if(!(m in mac)){ # if label was not in db (also not in + # arp table, but interfaces won't be + # there anyway) + firstDate[m] = date() + mac[m] = inter[m] = m + ip[m] = "NA" + bw[m "/in"]=bw[m "/out"]= 0 + } + } + bw[n]+=$2 + lastDate[m] = date() + } + } +} + +END { + if(mode=="noUpdate") exit + close(dbFile) + system("rm -f " dbFile) + print "#mac,ip,iface,in,out,total,first_date,last_date" > dbFile + OFS="," + for(i in mac) + print mac[i], ip[i], inter[i], bw[i "/in"], bw[i "/out"], total(i), firstDate[i], lastDate[i] > dbFile + close(dbFile) + # for hosts without rules + for(host in hosts) if(!inInterfaces(host)) newRule(host) +} \ No newline at end of file diff --git a/rooter/0optionalapps/ext-autoapn/Makefile b/rooter/0optionalapps/ext-autoapn/Makefile new file mode 100644 index 0000000..ef5fbc4 --- /dev/null +++ b/rooter/0optionalapps/ext-autoapn/Makefile @@ -0,0 +1,33 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-autoapn +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-autoapn + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + TITLE:=support for Automatic APN + PKGARCH:=all +endef + +define Package/ext-autoapn/description + Helper scripts to enable Automatic APN +endef + + +define Build/Compile +endef + +define Package/ext-autoapn/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,ext-autoapn)) diff --git a/rooter/0optionalapps/ext-autoapn/files/usr/lib/autoapn/apn.data b/rooter/0optionalapps/ext-autoapn/files/usr/lib/autoapn/apn.data new file mode 100644 index 0000000..88afe61 --- /dev/null +++ b/rooter/0optionalapps/ext-autoapn/files/usr/lib/autoapn/apn.data @@ -0,0 +1,2198 @@ +00101,phone,AT&TPHONETESTSIM,nil,1,nil,nil +001010,VZWINTERNET,TestInternet,nil,1,nil,nil +20201,internet,CosmoteWirelessInternet,nil,1,nil,nil +20205,internet.vodafone.gr,VfMobileInternet,nil,1,nil,nil +20209,myq,QInternet,nil,1,nil,nil +20210,gint.b-online.gr,WindInternet,nil,1,nil,nil +20402,internet.tele2.nl,Tele2GPRS,nil,1,nil,nil +20403,internet.mvno.mobi,MVNONL,mvno,1,mvno,1 +20404,mobiledata,JumpRoam,nil,1,nil,0 +20404,iot.truphone.com,Truphone,nil,1,nil,nil +20404,live.vodafone.com,VodafoneNL,vodafone,1,vodafone,1 +20404,VZWINTERNET,EHRPD-VZWRoamingInternet,nil,3,nil,nil +20408,iot.truphone.com,Truphone,nil,1,nil,nil +20404,internet.cs4glte.com,CSpireinternational,cs3g,1,Uniroam@inet.cs.com,3 +20404,admin.cs4glte.com,CSpireinternational,nil,1,nil,nil +20404,tethering.cs4glte.com,CSpireinternational,nil,1,nil,nil +20408,KPN4G.nl,KPN/Hi4GLTEMobielinternet,nil,1,nil,nil +20408,portalmmm.nl,KPN/HiMobielInternet,nil,1,nil,nil +20408,internet.mvno.mobi,MVNONL,mvno,1,mvno,1 +20408,rabo,RaboMobielInt.,nil,1,nil,nil +20404,net.hotm,HOTmobileInternet,nil,1,nil,nil +20412,internet,TelfortInternet,nil,1,nil,nil +20416,internet,T-MobileInternet,nil,1,nil,1 +20416,internet.ben,BenInternetAbonnee,nil,1,nil,nil +20416,basic.internet.ben.data,BenInternetPrePaid,nil,1,nil,nil +20420,internet,T-MobileInternet,nil,1,nil,1 +20433,iot.truphone.com,Truphone,nil,1,nil,nil +20601,INTERNET.PROXIMUS.BE,PxInternet,nil,1,nil,nil +20601,telenetwap.be,TelenetInternet,nil,1,nil,nil +20601,iijmio.jp,IIJmio(TypeI/Roaming),iij,1,mio@iij,3 +20601,vmobile.jp,vmobile.jp(Roaming),vmobile,1,vmobile@jp,3 +20605,telenetwap.be,TelenetInternet,nil,1,nil,nil +20610,mworld.be,MobistarInternet,nil,1,nil,nil +20610,netgprs.com,netgprs.com,tsl,1,tsl,nil +20620,gprs.base.be,BASEWAP,base,1,base,1 +20628,bicsapn,BICSInternet,nil,1,nil,nil +20801,orange,OrangeWorld,orange,1,orange,1 +20801,orange-mib,OrangeEntreprise,orange,1,orange,2 +20801,orange.fr,OrangeInternet,orange,1,orange,0 +20801,ofnew.fr,CarrefourWAP,orange,1,orange,1 +20801,coriolis,Coriolis,nil,1,nil,nil +20809,sl2sfr,SFRwebphone,nil,1,nil,nil +20809,websfr,SFRoptionmodem,nil,1,nil,nil +20809,pda.newcomobile.com,BeAliv,nil,1,nil,nil +20809,iot.truphone.com,Truphone,nil,1,nil,nil +20809,coriolis,Coriolis,nil,1,nil,nil +20810,sl2sfr,SFRwebphone,nil,1,nil,nil +20810,websfr,SFRoptionModem,nil,1,nil,0 +20810,fnetnrj,NRJWEB,nil,1,nil,nil +20810,internetnrj,INTERNETNRJ,nil,1,nil,0 +20810,wap65,AuchanWAP,nil,1,nil,nil +20810,wap66,WAPLeclercMobile,nil,1,nil,nil +20810,fnetcoriolis,CoriolisWAP,nil,1,nil,nil +20810,internetcoriolis,CoriolisWEB,nil,1,nil,0 +20810,wapdebitel,WEBLaPosteMobile,nil,1,nil,nil +20810,wap68,DartySurf&Mails,nil,1,nil,nil +20810,internet68,KeyyoMobileInternet,nil,1,nil,0 +20810,wap68,KeyyoMobileWap,nil,1,nil,0 +20810,wap66,WAPRegloMobile,nil,1,nil,0 +20812,iot.truphone.com,Truphone,nil,1,nil,nil +20815,free,Free,nil,1,nil,nil +20815,free.re,FreeReInt,nil,1,nil,nil +20815,iliad,IliadInt,nil,1,nil,nil +20817,bornsip,Legos,nil,1,nil,nil +20820,mmsbouygtel.com,BouyguesTelecom,nil,1,nil,nil +20822,mobiledata,mobiledata,nil,1,nil,nil +20822,netgprs.com,netgprs.com,tsl,1,tsl,nil +20823,virgin-mobile.fr,Virginmobile,nil,1,nil,nil +20826,fnetnrj,NRJWEB,nil,1,nil,nil +20827,coriolis,Coriolis,nil,1,nil,nil +21401,airtelwap.es,Internetmóvil,wap125,1,wap@wap,1 +21401,airtelnet.es,INTERNET,vodafone,1,vodafone,1 +21402,altecom.net,ALTECOM,nil,1,nil,nil +21402,fibracat.cat,FIBRACAT,nil,1,nil,nil +21403,orangeworld,OrangeInternetMóvil,orange,1,orange,1 +21403,internet,OrangeInternetPC,orange,1,orange,0 +21403,internet.euskaltel.mobi,EuskaltelInternet,EUSKALTEL,1,CLIENTE,1 +21403,CARREFOURINTERNET,Carrefour,nil,1,nil,1 +21403,internettph,HappyInternet,nil,1,nil,nil +21403,internet.racc.net,RACCINTERNET,RACC,1,CLIENTERACC,nil +21403,internetmas,MASMovilInternet,nil,1,nil,nil +21403,ibercominternet,IbercomInternet,nil,1,nil,nil +21403,jazzinternet,jazzinternet,nil,1,nil,nil +21404,internet,YoigoInternet,nil,1,nil,nil +21405,tuenti.com,Tuenti,tuenti,1,tuenti,1 +21405,inet.es,INETRoaming,nil,1,nil,nil +21406,airtelnet.es,INTERNETGPRS,vodafone,1,vodafone,nil +21406,internet.euskaltel.mobi,EuskaltelInternet,EUSKALTEL,1,CLIENTE,1 +21406,internet.mundo-r.com,InternetR,nil,1,nil,1 +21406,internet.telecable.es,TeleCableInternet,telecable,1,telecable,1 +21406,gprs.eroskimovil.es,EroskiMovilGPRS,wap125,1,wap@wap,1 +21406,gprs.pepephone.com,DUN,nil,1,nil,0 +21406,gprsmov.pepephone.com,Internet,nil,1,nil,0 +21407,telefonica.es,Movistar,telefonica,1,telefonica,1 +21407,jazzinternet,JazztelInternet,nil,1,nil,nil +21407,movistar.es,Conexióompartida,MOVISTAR,1,MOVISTAR,1 +21407,internet.t-2.net,T-2,nil,1,nil,nil +21408,internet.euskaltel.mobi,EuskaltelInternet,EUSKALTEL,1,CLIENTE,1 +21416,internet.telecable.es,TeleCableInternet,telecable,1,telecable,nil +21418,internet.ono.com,ONOInternet,nil,1,nil,nil +21419,orangeworld,internetsimyo,orange,1,orange,1 +21421,jazzinternet,jazzinternet,nil,1,nil,nil +21427,iot.truphone.com,Truphone,nil,1,nil,nil +21432,tuenti.com,Tuenti,tuenti,1,tuenti,3 +21434,inet.es,INETInternet,nil,1,nil,nil +21601,online,TelenorOnline,nil,1,nil,nil +21601,net,DjuiceNET,nil,1,nil,0 +21601,wap,DjuiceWAP,nil,1,nil,0 +21630,internet.telekom,T-MobileH,nil,1,nil,1 +21670,internet.vodafone.net,VodafoneInternet,nil,1,nil,0 +21670,wap.vodafone.net,VodafoneLive!,vodawap,1,vodawap,1 +21670,vitamax.internet.vodafone.net,VodafoneInternetVitaMAX,nil,1,nil,nil +21670,vitamax.wap.vodafone.net,VodafoneLive!VitaMAX,vodawap,1,vodawap,1 +21803,wap.eronet.ba,HTEronetWAP,nil,1,nil,nil +21803,gprs.eronet.ba,HTEronetGPRS,nil,1,nil,nil +21805,3g1,m,nil,1,nil,nil +21890,active.bhmobile.ba,BHMobileInternet,nil,1,nil,nil +21901,internet.ht.hr,T-MobileInternet,nil,1,nil,1 +21901,web.htgprs,bonbonInternet,nil,1,nil,1 +21902,internet.tele2.hr,Tele2,nil,1,nil,nil +21910,data.vip.hr,Broadband,38591,1,38591,1 +22001,internet,Telenorinternet,gprs,1,telenor,1 +22002,internet,TelenorMNEinternet,gprs,1,gprs,nil +22003,gprswap,mt,064,1,mts,1 +22003,gprsinternet,MTSInternetRS,064,1,mts,0 +22004,tmcg-wnw,T-MobileInternet,38267,1,38267,nil +20404,pda.stm.sk.ca,SaskTel,nil,1,nil,nil +20465,agms,agms,nil,1,nil,nil +22005,vipmobile,VipGPRS,vipmobile,1,vipmobile,1 +22201,wap.tim.it,TIMWAP,nil,1,nil,nil +22201,ibox.tim.it,TIMDUN(IT),nil,1,nil,0 +22201,internet.windmobile.ca,Internet,nil,1,nil,nil +22201,modem.iusacellgsm.mx,Modem,iusacellgsm,1,iusacellgsm,0 +22201,web.iusacellgsm.mx,Internet,iusacellgsm,1,iusacellgsm,0 +22201,web.noverca.it,NOVERCAWEB,nil,1,nil,0 +22210,mobile.vodafone.it,Acc.Internetdacell,nil,1,nil,nil +22210,web.omnitel.it,TetheringInternet,nil,1,nil,0 +22210,wap.postemobile.it,PosteMobile,nil,1,nil,0 +22210,internet.postemobile.it,PosteMobile(DUN),nil,1,nil,0 +22210,mobile.erg.it,ErgMobileWAP,nil,1,nil,0 +22250,iliad,Iliad,nil,1,nil,nil +22254,data.plintron.it,Plintron,nil,1,nil,1 +22288,internet.wind,WINDWEB,nil,1,nil,nil +22288,internet.windmobile.ca,Internet,nil,1,nil,nil +22299,tre.it,3,nil,1,nil,nil +22299,apn.fastweb.it,FastwebWEB,nil,1,nil,nil +22601,live.vodafone.com,Vodafonelive!,vodafone,1,live,1 +22601,live.pre.vodafone.com,Vodafonelive!PRE,vodafone,1,live,0 +22603,broadband,CosmoteConnectMobile,nil,1,nil,nil +22603,wnw,web'n'walk,wnw,1,wnw,1 +22605,internet,Digi.Mobil,nil,1,nil,1 +22606,broadband,CosmoteConnectMobile,nil,1,nil,nil +22606,wnw,web'n'walk,wnw,1,wnw,nil +22610,net,OrangeInternet,nil,1,nil,nil +22801,gprs.swisscom.ch,SwisscomServices,nil,1,nil,nil +22802,internet,Sunriselive,nil,1,nil,nil +22803,internet,OrangeInternet,nil,1,nil,nil +22803,netgprs.com,netgprs.com,tsl,1,tsl,nil +23001,internet.t-mobile.cz,T-MobileCZ,wap,1,wap,1 +23002,internet,O2internet,nil,1,nil,nil +23003,internet,Internet,nil,1,nil,nil +23101,internet,OrangeSK,nil,1,nil,nil +23101,orangewap,OrangeWorld,wap,1,wap,1 +23102,internet,T-Mobileinternet,nil,1,nil,1 +23106,o2internet,O2internet,nil,1,nil,nil +23201,a1.net,live!,ppp,1,ppp@a1plus.at,1 +23203,internet.t-mobile.at,T-MobileLTE,tm,1,t-mobile,1 +23205,drei.at,Planet3,nil,1,nil,nil +23207,web,tele.ringweb,web,1,web@telering.at,1 +23210,drei.at,Planet3,nil,1,nil,nil +23211,bob.at,data.bob,ppp,1,data@bob.at,1 +23212,web.yesss.at,yesss!,nil,1,nil,nil +23222,data.plintron.at,Plintron,nil,1,nil,1 +23401,internet,UBIQUISYS,nil,1,nil,nil +23402,mobile.o2.co.uk,O2MOBILEWEB,O2web,1,O2web,nil +23408,internet.btonephone.com,BTOnePhoneInternet,nil,1,nil,nil +23410,mobile.o2.co.uk,O2MobileWeb,password,1,o2web,nil +23410,payandgo.o2.co.uk,O2Pay&Go,password,1,payandgo,nil +23410,prepay.tesco-mobile.com,TESCO,password,1,tescowap,1 +23410,giffgaff.com,giffgaff,password,1,giffgaff,1 +23410,mobiledata,JumpUK,nil,1,nil,0 +23411,mobile.o2.co.uk,O2MOBILEWEB,O2web,1,O2web,nil +23415,wap.vodafone.co.uk,VodafoneUK,wap,1,wap,1 +23415,pp.vodafone.co.uk,VodafoneUKPrepay,wap,1,wap,1 +23415,asdamobiles.co.uk,ASDAWAP,wap,1,wap,1 +23415,payg.talkmobile.co.uk,TalkmobPAYGWAP,wap,1,wap,1 +23415,talkmobile.co.uk,TalkmobWAP,wap,1,wap,1 +23415,mobile.talktalk.co.uk,TalkTalkWAP,nil,1,nil,nil +23415,payg.mobilebysainsburys.co.uk,Sainsbury'sPAYG,nil,1,nil,1 +23415,uk.lebara.mobi,LebaraInternet,wap,1,wap,1 +23420,three.co.uk,3,nil,1,nil,nil +23420,3hotspot,3Hotspot,nil,1,nil,0 +23426,data.lycamobile.co.uk,Lycamobile,plus,1,lmuk,1 +23430,goto.virginmobile.uk,VirginMediaMobileInternet,nil,1,user,1 +23430,everywhere,EEInternet,secure,1,eesecure,1 +23430,internet.btonephone.com,BTOnePhoneInternet,nil,1,nil,nil +23433,tslpaygnet,Internet,nil,1,nil,0 +23433,everywhere,EEInternet,secure,1,eesecure,1 +23425,iot.truphone.com,Truphone,nil,1,nil,nil +23439,Jump,Jump,nil,1,nil,nil +23439,gamma.co.uk,GammaData,nil,1,nil,nil +23450,pepper,pepperWEB(Jersey),nil,1,nil,nil +23455,internet,C&WGuernseyInternet,nil,1,nil,nil +23458,3gpronto,3GHSDPA,nil,1,nil,nil +23458,web.manxpronto.net,ManxTelecomContractWEB,gprs,1,gprs,nil +23486,everywhere,EEInternet,secure,1,eesecure,1 +23594,3hotspot,3hotspot,nil,1,nil,0 +23594,three.co.uk,3,nil,1,nil,nil +23801,internet,DKTDC,nil,1,nil,0 +23801,internet,TDCInternet,nil,1,nil,nil +23801,wap,TELMOREWAP,nil,1,nil,0 +23802,Internet,TelenorInternet,nil,1,nil,nil +23806,data.tre.dk,3,nil,1,nil,nil +23820,www.internet.mtelia.dk,TeliaSurfPort,nil,1,nil,nil +23820,webSP,CallmeInternet,nil,1,nil,nil +23830,web.orange.dk,OrangeDE,nil,1,nil,nil +23877,Internet,TelenorInternet,nil,1,nil,nil +24001,online.telia.se,Telia,nil,1,nil,nil +24001,halebop.telia.se,HalebopInternet,nil,1,nil,nil +24002,data.tre.se,3,nil,1,nil,nil +24004,data.tre.se,3,nil,1,nil,nil +24005,4g.tele2.se,Tele2Internet,nil,1,nil,nil +24005,internet.tele2.se,Tele2Internet3G,nil,1,nil,nil +24005,online.telia.se,Telia,nil,1,nil,nil +24005,halebop.telia.se,HalebopInternet,nil,1,nil,nil +24006,internet,Internet,nil,1,nil,nil +24007,4g.tele2.se,Tele2Internet,nil,1,nil,nil +24007,internet.tele2.se,Tele2Internet3G,nil,1,nil,nil +24007,internet.tele2.no,Tele2Internet,wap,1,wap,1 +24007,Jump,Jump,nil,1,nil,nil +24007,gamma.co.uk,GammaData,nil,1,nil,nil +24008,internet.telenor.se,TelenorSE,nil,1,nil,nil +24009,com4,Com4,nil,1,nil,nil +24010,data.springmobil.se,Springdata,nil,1,nil,nil +240017,halebop.telia.se,HalebopInternet,nil,1,nil,nil +24024,4g.tele2.se,Tele2Internet,nil,1,nil,nil +24024,internet.tele2.se,Tele2Internet3G,nil,1,nil,nil +24201,internet.ventelo.no,VenteloInternett,nil,1,nil,nil +24201,telenor,Telenor,nil,1,nil,nil +24202,netcom,NetCom,nil,1,nil,nil +24204,internet.tele2.no,Tele2Internet,nil,1,nil,nil +24205,internet,NwNInternet,nil,1,nil,nil +24209,com4,Com4,nil,1,nil,nil +24403,internet,DNAInternet,nil,1,nil,nil +24404,internet,DNAInternet,nil,1,nil,nil +24405,internet,ElisaInternet,nil,1,nil,nil +24405,internet.saunalahti,SaunalahtiInternet,nil,1,nil,nil +24410,internet.song.fi,TDCInternet,songnet,1,song@internet,nil +24412,internet,DNAInternet,nil,1,nil,nil +24412,dnapro.fi,DNAProInternet,nil,1,nil,1 +24412,inet.tdc.fi,TDCInternetFinland,nil,1,nil,1 +24413,internet,DNAInternet,nil,1,nil,nil +24421,internet.saunalahti,SaunalahtiInternet,nil,1,nil,nil +24491,internet,SONERAInternet,nil,1,nil,nil +24601,omnitel,OmnitelInternet,omni,1,omni,1 +24602,wap,BiteInternet,nil,1,nil,nil +24608,mezon,Mezon,nil,1,nil,nil +24603,internet.tele2.lt,Tele2InternetLT,nil,1,nil,nil +246081,VZW800,Test800,nil,3,nil,nil +246081,VZWINTERNET,TestInternet,nil,3,nil,3 +246081,VZWINTERNET,TestInternet,nil,3,nil,nil +24681,VZW800,Test800,nil,3,nil,nil +24681,VZWINTERNET,TestInternet,nil,3,nil,3 +24681,VZWINTERNET,TestInternet,nil,3,nil,nil +24701,internet.lmt.lv,LMTInternet,nil,1,nil,nil +24702,internet.tele2.lv,Tele2LVInternet,nil,1,nil,nil +24705,internet,BiteLVInternet,nil,1,nil,nil +24705,wap,BiteLVWAP,nil,1,nil,nil +24801,internet.emt.ee,EMTInternet,nil,1,nil,nil +24801,wap.emt.ee,EMTWAP,nil,1,nil,nil +24801,send.ee,Send,nil,1,nil,nil +24802,internet,ElisaInternet,nil,1,nil,nil +24802,wap,ElisaWAP,nil,1,nil,nil +24803,internet.tele2.ee,Tele2Internet,nil,1,nil,nil +25001,internet.mts.ru,MTSInternet,mts,1,mts,1 +25002,internet,MegafonInternet,nil,1,nil,nil +25011,yota.ru,YOTAInternet,nil,1,nil,nil +25020,internet.tele2.ru,TELE2Internet,nil,1,nil,nil +25028,vodalte.ru,VODAinternet,nil,1,nil,nil +25062,m.tinkoff,TinkoffMobile,nil,1,nil,nil +25099,internet.beeline.ru,BeelineInternet,beeline,1,beeline,1 +25501,internet,MTS-internet,nil,1,nil,nil +25502,internet.beeline.ua,Beeline-internet,nil,1,nil,nil +25503,www.kyivstar.net,KyivstarInternet,internet,1,igprs,1 +25503,www.djuice.com.ua,DjuiceInternet,nil,1,nil,nil +25506,internet,Life,nil,1,nil,nil +25507,3g.utel.ua,UtelInternet,nil,1,nil,nil +25701,web.velcom.by,VelcomInternet,nil,1,nil,1 +25702,mts,MTSInternet,mts,1,mts,1 +25704,internet.life.com.by,life,nil,1,nil,1 +25901,wap.orange.md,Orange_Internet_GPRS,nil,1,nil,nil +25902,internet,MoldcellInternet,nil,1,nil,nil +25905,internet3g.unite.md,UniteInternetPrePay,nil,1,nil,nil +25905,internet.unite.md,UniteInternetPostPay,nil,1,nil,nil +26001,plus,PlusInternet,nil,1,nil,nil +26002,internet,T-mobile.pl,nil,1,nil,nil +26002,heyah.pl,heyahinternet,nil,1,nil,nil +26003,Internet,OrangeInternet,internet,1,internet,1 +26006,internet,PlayInternet,nil,1,nil,nil +26033,iot.truphone.com,Truphone,nil,1,nil,nil +26044,rebtel,Rebtel,nil,1,nil,nil +26201,internet.telekom,TelekomInternet,telekom,1,telekom,1 +26202,web.vodafone.de,VodafoneDE,nil,1,nil,nil +26202,home.vodafone.de,VodafoneDE,nil,1,nil,nil +26203,internet.eplus.de,E-PlusInternet,internet,1,eplus,1 +26207,internet,o2Internet,nil,1,nil,nil +26207,pinternet.interkom.de,o2InternetPrepaid,nil,1,nil,nil +26207,webmobil1,TchiboInternet,nil,1,nil,nil +26242,iot.truphone.com,Truphone,nil,1,nil,nil +26801,net2.vodafone.pt,VodafoneNet2,vodafone,1,vodafone,1 +26801,internet.vodafone.pt,vodafonePdun,nil,1,nil,0 +26803,umts,PortalOptimus,nil,1,nil,nil +26803,modem,OptimusHotSpot,nil,1,nil,nil +26806,internet,tmninternet,nil,1,nil,nil +27001,wap.pt.lu,LUXGSMWAP,wap,1,wap,nil +27002,internet,MTXC,nil,1,nil,nil +27077,internet,TangoWAP,tango,1,tango,nil +27077,netgprs.com,netgprs.com,tsl,1,tsl,nil +27099,orange.lu,Orange,nil,1,nil,nil +27201,live.vodafone.com,VodafoneIE,nil,1,nil,nil +27201,hs.vodafone.ie,VodafoneMISP,vodafone,1,vodafone,0 +27202,3iot.com,3Ireland,nil,1,nil,nil +27202,internet,3Ireland,nil,1,nil,0 +27203,data.mymeteor.ie,MeteorData,wap,1,my,1 +27205,3ireland.ie,3Ireland,nil,1,nil,nil +27211,tescomobile.liffeytelecom.com,Tesco,nil,1,nil,nil +27401,internet,SiminnInternet,nil,1,nil,nil +27402,gprs.is,VodafoneInternet,nil,1,nil,nil +27403,gprs.is,VodafoneInternet,nil,1,nil,0 +27411,net.nova.is,NetNova,nil,1,nil,nil +27801,internet,VodafoneMT,internet,1,internet,nil +28001,cytamobile,CYTA,nil,1,nil,nil +28010,internet,MTNInternet,nil,1,nil,nil +28020,ip.primetel,PrimeTel,nil,1,nil,nil +28401,inet-gprs.mtel.bg,MTel,nil,1,nil,nil +28403,internet.vivacom.bg,VIVACOMInternet,vivacom,1,vivacom,1 +28405,telenorbg,TelenorInternet,nil,1,nil,0 +28411,bulsat.com,bulsatcom,nil,1,nil,nil +28413,apn.maxtelecom.bg,MAXTELECOM,nil,1,nil,nil +28601,internet,TURKCELLINTERNET,nil,1,nil,nil +28602,internet,Vodafoneinternet,nil,1,nil,1 +28603,internet,AVEAINTERNET,nil,1,nil,1 +29001,internet,TeleInternet,nil,1,nil,nil +29340,internet.simobil.si,Si.mobilGPRS,internet,1,simobil,1 +29341,internet,MobilniInternet,internet,1,mobitel,1 +29364,internet.t-2.net,T2,nil,1,nil,nil +29370,internet.tusmobil.si,TusmobilInternet,internet,1,tusmobil,1 +29370,telemach.net,TelemachInternet,nil,1,nil,nil +29401,internet,T-MobileMKInternet,t-mobile,1,internet,nil +29402,Internet,Cosmofon,Internet,1,Internet,nil +29403,vipoperator,Internet,vipoperator,1,vipoperator,nil +29505,em,EMnify,nil,1,nil,nil +29509,em,EMnify,nil,1,nil,nil +29509,bicsapn,BICS,nil,1,nil,nil +29702,tmcg-wnw,T-MobileInternet,38267,1,38267,nil +302220,sp.telus.com,TELUS,nil,1,nil,nil +302220,isp.telus.com,TELUSTether,nil,1,nil,nil +302220,sp.koodo.com,Koodo,nil,1,nil,nil +302220,sp.mb.com,MobileInternet,nil,1,nil,nil +302220,isp.mb.com,TetheredMobileInternet,nil,1,nil,nil +302221,isp.telus.com,TELUSISP,nil,1,nil,nil +302221,sp.koodo.com,Koodo,nil,1,nil,nil +302221,isp.mb.com,TetheredPCMobile,nil,1,nil,nil +302320,wap.davewireless.com,MOWAP,nil,1,nil,nil +302270,wisp.mobi.eastlink.ca,Internet,nil,1,nil,nil +302370,ltedata.apn,FidoTethering,nil,1,nil,nil +302370,ltemobile.apn,FidoInternet,nil,1,nil,nil +302370,sp.mts,MTS,nil,1,nil,nil +302370,internet.mts,MTSTetheringS,nil,1,nil,nil +302490,internet.windmobile.ca,Internet,nil,1,nil,nil +302500,media.ng,Media,nil,1,nil,nil +302510,media.ng,Media,nil,1,nil,nil +302520,media.ng,Media,nil,1,nil,nil +302610,pda.bell.ca,BellMobility,nil,1,nil,nil +302610,ota.bell.ca,BellMobility,nil,1,nil,nil +302660,sp.mts,MTS,nil,1,nil,nil +302660,internet.mts,MTSTethering,nil,1,nil,nil +302720,ltemobile.apn,RogersLTE,nil,1,nil,nil +302720,chatrweb.apn,chatr,nil,1,nil,nil +302720,chatrisp.apn,ChatrTethering,nil,1,nil,nil +302720,ltedata.apn,TbaytelTethering,nil,1,nil,nil +302780,pda.stm.sk.ca,SaskTel,nil,1,nil,nil +310000,VZWINTERNET,Bluewire,nil,3,nil,nil +310020,union.wap.com,UnionWirelessData,nil,1,nil,nil +310004,internet,Verizon,nil,3,nil,3 +310028,VZWINTERNET,ALUTest-SIMInternet,nil,3,nil,nil +310030,private.centennialwireless.com,Internet,priv,1,privuser,nil +310032,VZWINTERNET,Itewire,nil,3,nil,nil +310035,VZWINTERNET,Etex,nil,3,nil,nil +310040,VZWINTERNET,Mta,nil,3,nil,nil +310050,VZWINTERNET,Alaskacomm,nil,3,nil,nil +310066,internet,U.S.Cellular,*,1,*,nil +310080,corrgprs,CorrWap,nil,1,nil,nil +310090,isp,Internet,nil,1,nil,nil +310100,isp.plateau,PLATWEB,nil,1,nil,nil +310120,sprint,Sprint,nil,1,nil,nil +310120,otasn,OTA,nil,1,nil,nil +310120,cinet.spcs,SPCSGlobal,nil,1,nil,nil +310130,VZWINTERNET,Carolinawest,nil,3,nil,nil +310150,ndo,internet,nil,1,nil,nil +310160,fast.t-mobile.com,T-MobileUS160,nil,1,nil,nil +310160,pcweb.tmobile.com,T-MobileUS160DUN,none,1,none,nil +310160,fast.metropcs.com,MetroPCS160,nil,1,nil,nil +310170,isp.cingular,DataConnect,nil,1,nil,nil +310180,internet.wcc.net,WCW-INTERNET,mmsc,1,13257630000,nil +310200,fast.t-mobile.com,T-MobileUS200,nil,1,nil,nil +310200,pcweb.tmobile.com,T-MobileUS200DUN,none,1,none,nil +310200,fast.metropcs.com,MetroPCS200,nil,1,nil,nil +310210,fast.t-mobile.com,T-MobileUS210,nil,1,nil,nil +310210,pcweb.tmobile.com,T-MobileUS210DUN,none,1,none,nil +310210,fast.metropcs.com,MetroPCS210,nil,1,nil,nil +310220,fast.t-mobile.com,T-MobileUS220,nil,1,nil,nil +310220,pcweb.tmobile.com,T-MobileUS220DUN,none,1,none,nil +310220,fast.metropcs.com,MetroPCS220,nil,1,nil,nil +310230,fast.t-mobile.com,T-MobileUS230,nil,1,nil,nil +310230,pcweb.tmobile.com,T-MobileUS230DUN,none,1,none,nil +310230,fast.metropcs.com,MetroPCS230,nil,1,nil,nil +310240,fast.t-mobile.com,T-MobileUS240,nil,1,nil,nil +310240,pcweb.tmobile.com,T-MobileUS240DUN,none,1,none,nil +310240,fast.metropcs.com,MetroPCS240,nil,1,nil,nil +310250,fast.t-mobile.com,T-MobileUS250,nil,1,nil,nil +310250,pcweb.tmobile.com,T-MobileUS250DUN,none,1,none,nil +310250,fast.metropcs.com,MetroPCS250,nil,1,nil,nil +310260,fast.t-mobile.com,T-MobileGPRS,nil,1,nil,nil +310260,h2g2,ProjectFi-T,none,1,none,nil +310260,fast.metropcs.com,MetroPCS260,nil,1,nil,nil +310260,simple,SIMPLE,nil,1,nil,nil +310260,wap.tracfone,TFWAP,nil,1,nil,nil +310260,wholesale,ConsumerCellular,nil,1,nil,nil +310270,fast.t-mobile.com,T-MobileUS270,nil,1,nil,nil +310270,pcweb.tmobile.com,T-MobileUS270DUN,none,1,none,nil +310270,fast.metropcs.com,MetroPCS270,nil,1,nil,nil +310280,agms,agms,nil,1,nil,nil +310300,fast.t-mobile.com,T-MobileUS300,nil,1,nil,nil +310300,pcweb.tmobile.com,T-MobileUS300DUN,none,1,none,nil +310300,fast.metropcs.com,MetroPCS300,nil,1,nil,nil +310310,fast.t-mobile.com,T-MobileUS310,nil,1,nil,nil +310310,pcweb.tmobile.com,T-MobileUS310DUN,none,1,none,nil +310310,fast.metropcs.com,MetroPCS310,nil,1,nil,nil +310320,isp.cellularoneaz.net,CellularOneNEAZISP,nil,1,nil,nil +310330,VZWINTERNET,Alltel2,nil,3,nil,nil +310360,VZWINTERNET,Pioneer,nil,3,nil,nil +310380,proxy,Cingular380ATT,nil,1,nil,nil +310380,agms.nl.gmm,AGMSGlobal,nil,1,nil,nil +310410,broadband,ATTNextgenphone,nil,1,nil,nil +310410,phone,ATTPhone,nil,1,nil,nil +310410,wap.cingular,ATTWAP,nil,1,nil,nil +310410,PRODATA,DefenseMobile,nil,1,nil,nil +310410,tfdata,TFDATA,nil,1,nil,nil +310420,wap.gocbw.com,CBWData,nil,1,nil,nil +310430,VZWINTERNET,Gci,nil,3,nil,nil +310450,internet.vedge.com,ViaeroConnect,nil,1,nil,nil +310470,isp.cingular,DataConnect,nil,1,nil,nil +310470,wap.cingular,MediaNet,CINGULAR1,1,WAP@CINGULARGPRS.COM,nil +310470,admin.4g.ntelos.com,nTelosOta,nil,1,nil,nil +310470,internet.4g.ntelos.com,nTelosWireless,nil,1,nil,nil +310470,tethering.4g.ntelos.com,nTelosTether,nil,1,nil,nil +310480,isp.cingular,DataConnect,nil,1,nil,nil +310480,wap.cingular,MediaNet,CINGULAR1,1,WAP@CINGULARGPRS.COM,nil +310490,fast.t-mobile.com,T-MobileUS490,nil,1,nil,nil +310490,pcweb.tmobile.com,T-MobileUS490DUN,none,1,none,nil +310490,fast.metropcs.com,MetroPCS490,nil,1,nil,nil +310530,fast.t-mobile.com,T-MobileUS530,nil,1,nil,nil +310530,pcweb.tmobile.com,T-MobileUS530DUN,none,1,none,nil +310530,fast.metropcs.com,MetroPCS530,nil,1,nil,nil +310560,nxtgenphone,ATTNextgenphone,nil,1,nil,nil +310570,internet,CellularOneSmartphone,nil,1,nil,nil +310580,VZWINTERNET,Inland,nil,3,nil,nil +310590,fast.t-mobile.com,T-MobileUS590,nil,1,nil,nil +310590,pcweb.tmobile.com,T-MobileUS590DUN,none,1,none,nil +310590,fast.metropcs.com,MetroPCS590,nil,1,nil,nil +310600,VZWINTERNET,Cellcom,nil,3,nil,nil +310610,internet.epictouch,EpicINT,nil,1,nil,nil +310640,fast.t-mobile.com,T-MobileUS640,nil,1,nil,nil +310640,pcweb.tmobile.com,T-MobileUS640DUN,none,1,none,nil +310640,fast.metropcs.com,MetroPCS640,nil,1,nil,nil +310660,fast.t-mobile.com,T-MobileUS660,nil,1,nil,nil +310660,pcweb.tmobile.com,T-MobileUS660DUN,none,1,none,nil +310660,fast.metropcs.com,MetroPCS660,nil,1,nil,nil +31069,iot.truphone.com,Truphone,nil,1,nil,nil +310720,internet.com,RogersInternet,nil,1,nil,nil +310750,VZWINTERNET,Appalachian,nil,3,nil,nil +310770,i2.iwireless.com,Web2,nil,1,nil,nil +310770,wap1.iwireless.com,Web1,nil,1,nil,nil +310800,fast.t-mobile.com,T-MobileUS800,nil,1,nil,nil +310800,pcweb.tmobile.com,T-MobileUS800DUN,none,1,none,nil +310800,fast.metropcs.com,MetroPCS800,nil,1,nil,nil +310840,isp,Internet,nil,1,nil,nil +310880,wapdtcw.com,DTCdtcwap,nil,1,nil,nil +310900,VZWINTERNET,Midrivers,nil,3,nil,nil +310910,wap.firstcellular.com,WOW_WAP,nil,1,nil,nil +310920,VZWINTERNET,Jamesvalley,nil,3,nil,nil +310930,VZWINTERNET,CopperValley,nil,3,nil,nil +310960,VZWINTERNET,Nntcwire,nil,3,nil,nil +311050,VZWINTERNET,Thumbcellular,nil,3,nil,nil +311070,VZWINTERNET,Elementmobile,nil,3,nil,nil +311080,PINE,PINEWAP,nil,1,nil,nil +311140,VZWINTERNET,Sprocket,nil,3,nil,nil +311190,isp.cellular1.net,ISP,nil,1,nil,nil +311190,broadband.cellular1.net,Tether,nil,1,nil,nil +311210,internet.farmerswireless.com,FarmersGPRS,nil,1,nil,nil +311220,usccinternet,U.S.Cellular,nil,1,nil,nil +311221,usccinternet,U.S.Cellular,nil,1,nil,nil +311222,usccinternet,U.S.Cellular,nil,1,nil,nil +311223,usccinternet,U.S.Cellular,nil,1,nil,nil +311224,usccinternet,U.S.Cellular,nil,1,nil,nil +311225,usccinternet,U.S.Cellular,nil,1,nil,nil +311226,usccinternet,U.S.Cellular,nil,1,nil,nil +311227,usccinternet,U.S.Cellular,nil,1,nil,nil +311228,usccinternet,U.S.Cellular,nil,1,nil,nil +311229,usccinternet,U.S.Cellular,nil,1,nil,nil +311230,admin.cs4glte.com,CSpireota,nil,1,nil,nil +311230,internet.cs4glte.com,CSpireinternet,nil,1,nil,nil +311230,tethering.cs4glte.com,CSpiretether,nil,1,nil,nil +311310,VZWINTERNET,Leaco,nil,3,nil,nil +311340,VZWINTERNET,Illinoisvalley,nil,3,nil,nil +311350,VZWINTERNET,Nemont,nil,3,nil,nil +311370,web.gci,GCIWEB,nil,1,nil,nil +311370,web.acs,ACSWEB,nil,1,nil,nil +311410,VZWINTERNET,Chatmobrsa2,nil,3,nil,nil +311420,VZWINTERNET,Northwestcell,nil,3,nil,nil +311430,VZWINTERNET,Chatmobrsa1,nil,3,nil,nil +311440,VZWINTERNET,Bluegrass,nil,3,nil,nil +311450,VZWINTERNET,Ptci,nil,3,nil,nil +311500,wap,24-7WAP,nil,1,nil,nil +311530,mms.mymobiletxt.com,Blaze,nil,1,nil,nil +311530,wap.mymobiletxt.com,DuetInternet,nil,1,nil,nil +311580,usccinternet,U.S.Cellular,nil,1,nil,nil +311581,usccinternet,U.S.Cellular,nil,1,nil,nil +311582,usccinternet,U.S.Cellular,nil,1,nil,nil +311583,usccinternet,U.S.Cellular,nil,1,nil,nil +311584,usccinternet,U.S.Cellular,nil,1,nil,nil +311585,usccinternet,U.S.Cellular,nil,1,nil,nil +311586,usccinternet,U.S.Cellular,nil,1,nil,nil +311587,usccinternet,U.S.Cellular,nil,1,nil,nil +311588,usccinternet,U.S.Cellular,nil,1,nil,nil +311589,usccinternet,U.S.Cellular,nil,1,nil,nil +311600,VZWINTERNET,Cox,nil,3,nil,nil +311610,VZWINTERNET,Srtcomm,nil,3,nil,nil +311650,VZWINTERNET,Unitedwireless,nil,3,nil,nil +311670,VZWINTERNET,Pinebelt,nil,3,nil,nil +311740,akcell.mobi,TelAlaskaCellular,nil,1,nil,nil +311750,CdmaNai,Cleartalk,nil,1,nil,3 +311750,home.netamerica.com,ClearTalkLTE,nil,1,nil,nil +311910,mymn4g.net,MobileNation,nil,1,nil,nil +311920,VZWINTERNET,Charitonvalley,nil,3,nil,nil +311930,internet.syringawireless.com,SyringaWireless,nil,1,nil,nil +312420,admin.lte.ntwls.com,NexTechOta,nil,1,nil,nil +312420,internet.lte.ntwls.com,NexTechWireless,nil,1,nil,nil +312420,modem.lte.ntwls.com,NexTechTether,nil,1,nil,nil +312570,BlueHotspot,BlueWireless,wirelessblue,1,%M@dun.bluehandset.com,nil +330000,VZWINTERNET,Openmobile,nil,3,nil,nil +330110,lte.claropr.com,PuertoRico,nil,1,nil,1 +334020,internet.itelcel.com,Internet,webgprs2002,1,webgprs,1 +33403,internet.movistar.mx,MovistarINTERNET,movistar,1,movistar,1 +334030,internet.movistar.mx,MovistarINTERNET,movistar,1,movistar,1 +334050,web.iusacellgsm.mx,IusacellInternet,iusacellgsm,1,iusacellgsm,nil +33450,modem.iusacellgsm.mx,Modem,iusacellgsm,1,iusacellgsm,1 +334090,location.nexteldata.com.mx,Localización,nil,1,nil,0 +334090,modem.nexteldata.com.mx,Internet,nil,1,nil,0 +334090,wap.nexteldata.com.mx,Navegación,nil,1,nil,0 +33805,web,INTERNETDigicel,nil,1,nil,nil +338050,web,INTERNETDigicel,nil,1,nil,nil +33818,internet,LimeInternetPostpaid,nil,1,nil,nil +33818,ppinternet,LimeInternetPrepaid,nil,1,nil,nil +338180,internet,LimeInternetPostpaid,nil,1,nil,nil +338180,ppinternet,LimeInternetPrepaid,nil,1,nil,nil +338070,internet.ideasclaro.com.jm,ClaroWeb,nil,1,nil,1 +338180,internet,LimeInternetPostpaid,nil,1,nil,1 +34001,orangeweb,OrangeWorldCaraïbe,orange,1,orange,nil +34001,orangeweb,Orangeweb,orange,1,orange,1 +34020,web.digicelfr.com,DigicelWeb,nil,1,nil,nil +34260,internet,LimeInternetPostpaid,nil,1,nil,nil +342600,internet,Barbado,nil,1,nil,1 +34492,internet,LimeInternetPostpaid,nil,1,nil,nil +344920,internet,Antigua,nil,1,nil,1 +34614,internet,LimeInternetPostpaid,nil,1,nil,nil +346140,internet,CaymanIslands,nil,1,nil,1 +34817,internet,LimeInternetPostpaid,nil,1,nil,nil +34877,wap.digicelbvi.com,Bvi,nil,1,nil,1 +34877,wap.digicelbvi.com,Bvi,wapbvi,1,wapbvi,1 +348170,internet,Bvi,nil,1,nil,1 +35211,internet,LimeInternetPostpaid,nil,1,nil,nil +352110,internet,Grenada,nil,1,nil,1 +35486,internet,LimeInternetPostpaid,nil,1,nil,nil +354860,internet,Monserrat,nil,1,nil,1 +35611,internet,LimeInternetPostpaid,nil,1,nil,nil +356110,internet,StKittsAndNevis,nil,1,nil,1 +35811,internet,LimeInternetPostpaid,nil,1,nil,nil +36011,internet,LimeInternetPostpaid,nil,1,nil,nil +358110,internet,StLucia,nil,1,nil,1 +360110,internet,StVincent,nil,1,nil,1 +36269,web.digicelcuracao.com,Curacao,nil,1,nil,1 +36269,wap,Curacao,nil,1,nil,1 +36302,web.digicelaruba.com,INTERNETAruba,nil,1,nil,1 +363020,web.digicelaruba.com,INTERNETAruba,nil,1,nil,1 +36449,pda.newcomobile.com,BeAliv,nil,1,nil,nil +36584,internet,LimeInternetPostpaid,nil,1,nil,nil +365840,internet,Anguilla,nil,1,nil,1 +36611,internet,LimeInternetPostpaid,nil,1,nil,nil +366110,internet,Dominica,nil,1,nil,1 +36801,internet,Internet,nil,1,nil,nil +37001,orangeinternet,OrangeInternet(LTE),nil,1,nil,nil +37001,orangenet.com.do,Orangenet(3G),nil,1,nil,nil +37002,internet.ideasclaro.com.do,InternetMóvilClaro,nil,1,nil,nil +370020,internet.ideasclaro.com.do,InternetMóvilClaro,nil,1,nil,nil +37004,edge.viva.net.do,VivaEdge(GSM),viva,1,viva,1 +37202,wap.digicelha.com,Haiti,nil,1,nil,1 +37202,wap.digicelha.com,Haiti,wap01ha,1,wapha,1 +37203,natcom,NATCOMINTERNET,nil,1,nil,nil +37412,internet,Bmobileinternet,nil,1,nil,1 +374120,internet,Bmobileinternet,nil,1,nil,1 +374121,internet,Bmobileinternet,nil,1,nil,1 +374122,internet,Bmobileinternet,nil,1,nil,1 +374123,internet,Bmobileinternet,nil,1,nil,1 +374124,internet,Bmobileinternet,nil,1,nil,1 +374125,internet,Bmobileinternet,nil,1,nil,1 +374126,internet,Bmobileinternet,nil,1,nil,1 +374127,internet,Bmobileinternet,nil,1,nil,1 +374128,internet,Bmobileinternet,nil,1,nil,1 +374129,internet,Bmobileinternet,nil,1,nil,1 +37413,web.digiceltt.com,INTERNETTrinidad,nil,1,nil,1 +374130,web.digiceltt.com,INTERNETTrinidad,nil,1,nil,1 +37635,internet,LimeInternetPostpaid,nil,1,nil,nil +376350,internet,TurksAndCaicos,nil,1,nil,1 +40001,default,Azercell,nil,1,nil,nil +40002,default,Bakcell,nil,1,nil,nil +40003,default,FONEX,nil,1,nil,nil +40004,default,NarMobile,nil,1,nil,nil +40101,internet.beeline.kz,BeelineInternet,beeline,1,@internet.beeline,1 +40101,internet.dos.kz,DOSInternet,nil,1,nil,nil +40102,internet,KcellInternet,nil,1,nil,nil +40107,internet,ALTELINTERNET,nil,1,nil,nil +40177,internet,Tele2Internet,nil,1,nil,nil +40211,default,B-Mobile,nil,1,nil,nil +40277,ticlnet,TashiCell,nil,1,nil,nil +40401,portalnmms,Vodafonelive,nil,1,nil,nil +40401,www,Vodafonemobileconnect,nil,1,nil,nil +40402,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40402,airtelgprs.com,MobileOffice,nil,1,nil,nil +40403,airtelgprs.com,MobileOffice,nil,1,nil,nil +40403,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40404,internet,Idea_Internet,nil,1,nil,nil +40404,imis,IDEAGPRS,nil,1,nil,nil +40405,www,Vodafonemobileconnect,nil,1,nil,nil +40405,portalnmms,Vodafonelive,nil,1,nil,nil +40407,internet,Idea_Internet,nil,1,nil,nil +40407,imis,IDEAGPRS,nil,1,nil,nil +40409,smartnet,RelianceNet,nil,1,nil,nil +40409,smartwap,RelianceWAP,nil,1,nil,1 +40410,airtelgprs.com,MobileOffice,nil,1,nil,nil +40410,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40411,www,Vodafonemobileconnect,nil,1,nil,nil +40411,portalnmms,Vodafonelive,nil,1,nil,nil +40412,internet,Idea_Internet,nil,1,nil,nil +40412,imis,IDEAGPRS,nil,1,nil,nil +40413,www,Vodafonemobileconnect,nil,1,nil,nil +40413,portalnmms,Vodafonelive,nil,1,nil,nil +40414,internet,Idea_Internet,nil,1,nil,nil +40414,imis,IDEAGPRS,nil,1,nil,nil +40415,www,Vodafonemobileconnect,nil,1,nil,nil +40415,portalnmms,Vodafonelive,nil,1,nil,nil +40416,airtelgprs.com,MobileOffice,nil,1,nil,nil +40416,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40417,aircelwebpost,Aircel-GPRS-Postpaid,nil,1,nil,nil +40417,aircelwappost,PocketInternet-Postpaid,nil,1,nil,nil +40417,aircelwap,PocketInternet-Prepaid,nil,1,nil,nil +40417,aircelweb,Aircel-GPRS-Prepaid,nil,1,nil,nil +40417,aircelgprs,AircelInternet(40417),nil,1,nil,nil +40418,smartnet,RelianceNet,nil,1,nil,nil +40418,smartwap,RelianceWAP,nil,1,nil,1 +40418,rcomnet,RelianceInternet(40418),nil,1,nil,nil +40419,internet,Idea_Internet,nil,1,nil,nil +40419,imis,IDEAGPRS,nil,1,nil,nil +40420,www,Vodafonemobileconnect,nil,1,nil,nil +40420,portalnmms,Vodafonelive,nil,1,nil,nil +40421,www,LoopMobile,nil,1,nil,nil +40422,internet,Idea_Internet,nil,1,nil,nil +40422,imis,IDEAGPRS,nil,1,nil,nil +40424,internet,Idea_Internet,nil,1,nil,nil +40424,imis,IDEAGPRS,nil,1,nil,nil +40425,aircelwebpost,Aircel-GPRS-Postpaid,nil,1,nil,nil +40425,aircelwappost,PocketInternet-Postpaid,nil,1,nil,nil +40425,aircelwap,PocketInternet-Prepaid,nil,1,nil,nil +40425,aircelweb,Aircel-GPRS-Prepaid,nil,1,nil,nil +40425,aircelgprs,AircelInternet(40425),nil,1,nil,nil +40427,www,Vodafonemobileconnect,nil,1,nil,nil +40427,portalnmms,Vodafonelive,nil,1,nil,nil +40428,aircelwebpost,Aircel-GPRS-Postpaid,nil,1,nil,nil +40428,aircelwappost,PocketInternet-Postpaid,nil,1,nil,nil +40428,aircelwap,PocketInternet-Prepaid,nil,1,nil,nil +40428,aircelweb,Aircel-GPRS-Prepaid,nil,1,nil,nil +40428,aircelgprs,AircelInternet(40428),nil,1,nil,nil +40429,aircelwebpost,Aircel-GPRS-Postpaid,nil,1,nil,nil +40429,myaircelpost,PocketInternet-Postpaid,nil,1,nil,nil +40429,myaircel,PocketInternet-Prepaid,nil,1,nil,nil +40429,aircelweb,Aircel-GPRS-Prepaid,nil,1,nil,nil +40429,aircelgprs,AircelInternet(40429),nil,1,nil,nil +40429,aircelwap,AircelWAP(40429),nil,1,nil,nil +40430,www,Vodafonemobileconnect,nil,1,nil,nil +40430,portalnmms,Vodafonelive,nil,1,nil,nil +40431,airtelgprs.com,MobileOffice,nil,1,nil,nil +40431,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40433,aircelwebpost,Aircel-GPRS-Postpaid,nil,1,nil,nil +40433,myaircelpost,PocketInternet-Postpaid,nil,1,nil,nil +40433,myaircel,PocketInternet-Prepaid,nil,1,nil,nil +40433,aircelweb,Aircel-GPRS-Prepaid,nil,1,nil,nil +40433,aircelgprs,AircelInternet(40433),nil,1,nil,nil +40433,aircelwap,AircelWAP(40433),nil,1,nil,nil +40434,bsnlnet,bsnlnet,nil,1,nil,1 +40434,bsnllive,bsnllive,nil,1,nil,nil +40435,aircelwebpost,Aircel-GPRS-Postpaid,nil,1,nil,nil +40435,aircelwappost,PocketInternet-Postpaid,nil,1,nil,nil +40435,aircelwap,PocketInternet-Prepaid,nil,1,nil,nil +40435,aircelweb,Aircel-GPRS-Prepaid,nil,1,nil,nil +40435,aircelgprs,AircelInternet(40435),nil,1,nil,nil +40436,smartnet,RelianceNet,nil,1,nil,nil +40436,smartwap,RelianceWAP,nil,1,nil,1 +40436,rcomnet,RelianceInternet(40436),nil,1,nil,nil +40437,aircelwebpost,Aircel-GPRS-Postpaid,nil,1,nil,nil +40437,aircelwappost,PocketInternet-Postpaid,nil,1,nil,nil +40437,aircelwap,PocketInternet-Prepaid,nil,1,nil,nil +40437,aircelweb,Aircel-GPRS-Prepaid,nil,1,nil,nil +40437,aircelgprs,AircelInternet(40437),nil,1,nil,nil +40438,bsnlnet,bsnlnet,nil,1,nil,nil +40438,bsnllive,bsnllive,nil,1,nil,nil +40440,airtelgprs.com,MobileOffice,nil,1,nil,nil +40440,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40441,aircelgprs.po,Aircel-GPRS-Postpaid,nil,1,nil,nil +40441,aircelgprs.pr,Aircel-GPRS-Prepaid,nil,1,nil,nil +40441,aircelwap.po,PocketInternet-Postpaid,nil,1,nil,nil +40441,aircelwap.pr,PocketInternet-Prepaid,nil,1,nil,nil +40441,aircelgprs,AircelInternet(40441),nil,1,nil,nil +40441,aircelwap,AircelWAP(40441),nil,1,nil,nil +40442,aircelgprs.po,Aircel-GPRS-Postpaid,nil,1,nil,nil +40442,aircelgprs.pr,Aircel-GPRS-Prepaid,nil,1,nil,nil +40442,aircelwap.po,PocketInternet-Postpaid,nil,1,nil,nil +40442,aircelwap.pr,PocketInternet-Prepaid,nil,1,nil,nil +40442,aircelgprs,AircelInternet(40442),nil,1,nil,nil +40443,www,Vodafonemobileconnect,nil,1,nil,nil +40443,portalnmms,Vodafonelive,nil,1,nil,nil +40444,internet,Idea_Internet,nil,1,nil,nil +40444,imis,IDEAGPRS,nil,1,nil,nil +40445,airtelgprs.com,MobileOffice,nil,1,nil,nil +40445,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40446,www,Vodafonemobileconnect,nil,1,nil,nil +40446,portalnmms,Vodafonelive,nil,1,nil,nil +40449,airtelgprs.com,MobileOffice,nil,1,nil,nil +40449,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40450,smartnet,RelianceNet,nil,1,nil,nil +40450,smartwap,RelianceWAP,nil,1,nil,1 +40451,bsnlnet,bsnlnet,nil,1,nil,nil +40451,bsnllive,bsnllive,nil,1,nil,nil +40452,smartnet,RelianceNet,nil,1,nil,nil +40452,smartwap,RelianceWAP,nil,1,nil,1 +40453,bsnlnet,bsnlnet,nil,1,nil,nil +40453,bsnllive,bsnllive,nil,1,nil,nil +40454,bsnlnet,bsnlnet,nil,1,nil,nil +40454,bsnllive,bsnllive,nil,1,nil,nil +40455,bsnlnet,bsnlnet,nil,1,nil,nil +40455,bsnllive,bsnllive,nil,1,nil,nil +40456,internet,Idea_Internet,nil,1,nil,nil +40456,imis,IDEAGPRS,nil,1,nil,nil +40457,bsnlnet,bsnlnet,nil,1,nil,nil +40457,bsnllive,bsnllive,nil,1,nil,nil +40458,bsnlnet,bsnlnet,nil,1,nil,nil +40458,bsnllive,bsnllive,nil,1,nil,nil +40459,bsnlnet,bsnlnet,nil,1,nil,nil +40459,bsnllive,bsnllive,nil,1,nil,nil +40460,www,Vodafonemobileconnect,nil,1,nil,nil +40460,portalnmms,Vodafonelive,nil,1,nil,nil +40462,bsnlnet,bsnlnet,nil,1,nil,nil +40462,bsnllive,bsnllive,nil,1,nil,nil +40464,bsnlnet,bsnlnet,nil,1,nil,nil +40464,bsnllive,bsnllive,nil,1,nil,nil +40466,bsnlnet,bsnlnet,nil,1,nil,nil +40466,bsnllive,bsnllive,nil,1,nil,nil +40467,smartnet,RelianceNet,nil,1,nil,nil +40467,smartwap,RelianceWAP,nil,1,nil,1 +40468,mtnl.net,MTNL,mtnl123,1,mtnl,0 +40469,mtnl.net,MTNL,mtnl123,1,mtnl,0 +40470,airtelgprs.com,MobileOffice,nil,1,nil,nil +40470,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40471,bsnlnet,bsnlnet,nil,1,nil,nil +40471,bsnllive,bsnllive,nil,1,nil,nil +40472,bsnlnet,bsnlnet,nil,1,nil,nil +40472,bsnllive,bsnllive,nil,1,nil,nil +40473,bsnlnet,bsnlnet,nil,1,nil,nil +40473,bsnllive,bsnllive,nil,1,nil,nil +40474,bsnlnet,bsnlnet,nil,1,nil,nil +40474,bsnllive,bsnllive,nil,1,nil,nil +40475,bsnlnet,bsnlnet,nil,1,nil,nil +40475,bsnllive,bsnllive,nil,1,nil,nil +40476,bsnlnet,bsnlnet,nil,1,nil,nil +40476,bsnllive,bsnllive,nil,1,nil,nil +40477,bsnlnet,bsnlnet,nil,1,nil,nil +40477,bsnllive,bsnllive,nil,1,nil,nil +40478,internet,Idea_Internet,nil,1,nil,nil +40478,imis,IDEAGPRS,nil,1,nil,nil +40479,bsnlnet,bsnlnet,nil,1,nil,nil +40479,bsnllive,bsnllive,nil,1,nil,nil +40480,bsnlnet,bsnlnet,nil,1,nil,nil +40480,bsnllive,bsnllive,nil,1,nil,nil +40481,bsnlnet,bsnlnet,nil,1,nil,nil +40481,bsnllive,bsnllive,nil,1,nil,nil +40482,internet,Idea_Internet,nil,1,nil,nil +40482,imis,IDEAGPRS,nil,1,nil,nil +40483,smartnet,RelianceNet,nil,1,nil,nil +40483,smartwap,RelianceWAP,nil,1,nil,1 +40484,www,Vodafonemobileconnect,nil,1,nil,nil +40484,portalnmms,Vodafonelive,nil,1,nil,nil +40485,smartnet,RelianceNet,nil,1,nil,nil +40485,smartwap,RelianceWAP,nil,1,nil,1 +40486,www,Vodafonemobileconnect,nil,1,nil,nil +40486,portalnmms,Vodafonelive,nil,1,nil,nil +40487,internet,Idea_Internet,nil,1,nil,nil +40487,imis,IDEAGPRS,nil,1,nil,nil +40488,www,Vodafonemobileconnect,nil,1,nil,nil +40488,portalnmms,Vodafonelive,nil,1,nil,nil +40489,internet,Idea_Internet,nil,1,nil,nil +40489,imis,IDEAGPRS,nil,1,nil,nil +40490,airtelgprs.com,MobileOffice,nil,1,nil,nil +40490,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40491,aircelwebpost,Aircel-GPRS-Postpaid,nil,1,nil,nil +40491,aircelwappost,PocketInternet-Postpaid,nil,1,nil,nil +40491,aircelwap,PocketInternet-Prepaid,nil,1,nil,nil +40491,aircelweb,Aircel-GPRS-Prepaid,nil,1,nil,nil +40492,airtelgprs.com,MobileOffice,nil,1,nil,nil +40492,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40493,airtelgprs.com,MobileOffice,nil,1,nil,nil +40493,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40494,airtelgprs.com,MobileOffice,nil,1,nil,nil +40494,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40495,airtelgprs.com,MobileOffice,nil,1,nil,nil +40495,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40496,airtelgprs.com,MobileOffice,nil,1,nil,nil +40496,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40497,airtelgprs.com,MobileOffice,nil,1,nil,nil +40497,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40498,airtelgprs.com,MobileOffice,nil,1,nil,nil +40498,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40501,rcomnet,Netconnect,nil,1,nil,nil +40501,rcomwap,RelianceMbWorld,nil,1,nil,nil +40503,rcomnet,Netconnect,nil,1,nil,nil +40503,rcomwap,RelianceMbWorld,nil,1,nil,nil +40504,rcomnet,Netconnect,nil,1,nil,nil +40504,rcomwap,RelianceMbWorld,nil,1,nil,nil +40505,rcomnet,Netconnect,nil,1,nil,nil +40505,rcomwap,RelianceMbWorld,nil,1,nil,nil +40506,rcomnet,Netconnect,nil,1,nil,nil +40506,rcomwap,RelianceMbWorld,nil,1,nil,nil +40507,rcomnet,Netconnect,nil,1,nil,nil +40507,rcomwap,RelianceMbWorld,nil,1,nil,nil +40508,rcomnet,Netconnect,nil,1,nil,nil +40508,rcomwap,RelianceMbWorld,nil,1,nil,nil +40509,rcomnet,Netconnect,nil,1,nil,nil +40509,rcomwap,RelianceMbWorld,nil,1,nil,nil +40510,rcomnet,Netconnect,nil,1,nil,nil +40510,rcomwap,RelianceMbWorld,nil,1,nil,nil +40511,rcomnet,Netconnect,nil,1,nil,nil +40511,rcomwap,RelianceMbWorld,nil,1,nil,nil +40512,rcomnet,Netconnect,nil,1,nil,nil +40512,rcomwap,RelianceMbWorld,nil,1,nil,nil +40513,rcomnet,Netconnect,nil,1,nil,nil +40513,rcomwap,RelianceMbWorld,nil,1,nil,nil +40514,rcomnet,Netconnect,nil,1,nil,nil +40514,rcomwap,RelianceMbWorld,nil,1,nil,nil +40515,rcomnet,Netconnect,nil,1,nil,nil +40515,rcomwap,RelianceMbWorld,nil,1,nil,nil +40517,rcomnet,Netconnect,nil,1,nil,nil +40517,rcomwap,RelianceMbWorld,nil,1,nil,nil +40518,rcomnet,Netconnect,nil,1,nil,nil +40518,rcomwap,RelianceMbWorld,nil,1,nil,nil +40519,rcomnet,Netconnect,nil,1,nil,nil +40519,rcomwap,RelianceMbWorld,nil,1,nil,nil +40520,rcomnet,Netconnect,nil,1,nil,nil +40520,rcomwap,RelianceMbWorld,nil,1,nil,nil +40521,rcomnet,Netconnect,nil,1,nil,nil +40521,rcomwap,RelianceMbWorld,nil,1,nil,nil +40522,rcomnet,Netconnect,nil,1,nil,nil +40522,rcomwap,RelianceMbWorld,nil,1,nil,nil +40523,rcomnet,Netconnect,nil,1,nil,nil +40523,rcomwap,RelianceMbWorld,nil,1,nil,nil +405025,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405025,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405026,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405026,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405027,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405027,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405028,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405028,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405029,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405029,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405030,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405030,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405031,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405031,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405032,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405032,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405033,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405033,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405034,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405034,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405035,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405035,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405036,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405036,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405037,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405037,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405038,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405038,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405039,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405039,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405040,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405040,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405041,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405041,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405042,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405042,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405043,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405043,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405044,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405044,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405045,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405045,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405046,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405046,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +405047,TATA.DOCOMO.INTERNET,TATADOCOMOINTERNET,nil,1,nil,nil +405047,TATA.DOCOMO.DIVE.IN,TATADOCOMODIVE-IN,nil,1,nil,nil +40551,airtelgprs.com,MobileOffice,nil,1,nil,nil +40551,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40552,airtelgprs.com,MobileOffice,nil,1,nil,nil +40552,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40553,airtelgprs.com,MobileOffice,nil,1,nil,nil +40553,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40554,airtelgprs.com,MobileOffice,nil,1,nil,nil +40554,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40555,airtelgprs.com,MobileOffice,nil,1,nil,nil +40555,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40556,airtelgprs.com,MobileOffice,nil,1,nil,nil +40556,airtelfun.com,AIRTELLIVE,nil,1,nil,nil +40566,www,Vodafonemobileconnect,nil,1,nil,nil +40566,portalnmms,Vodafonelive,nil,1,nil,nil +40567,www,Vodafonemobileconnect,nil,1,nil,nil +40567,portalnmms,Vodafonelive,nil,1,nil,nil +40570,internet,Idea_Internet,nil,1,nil,nil +40570,imis,IDEAGPRS,nil,1,nil,nil +405750,www,Vodafonemobileconnect,nil,1,nil,nil +405750,portalnmms,Vodafonelive,nil,1,nil,nil +405751,www,Vodafonemobileconnect,nil,1,nil,nil +405751,portalnmms,Vodafonelive,nil,1,nil,nil +405752,www,Vodafonemobileconnect,nil,1,nil,nil +405752,portalnmms,Vodafonelive,nil,1,nil,nil +405753,www,Vodafonemobileconnect,nil,1,nil,nil +405753,portalnmms,Vodafonelive,nil,1,nil,nil +405754,www,Vodafonemobileconnect,nil,1,nil,nil +405754,portalnmms,Vodafonelive,nil,1,nil,nil +405755,www,Vodafonemobileconnect,nil,1,nil,nil +405755,portalnmms,Vodafonelive,nil,1,nil,nil +405756,www,Vodafonemobileconnect,nil,1,nil,nil +405756,portalnmms,Vodafonelive,nil,1,nil,nil +405799,internet,Idea_Internet,nil,1,nil,nil +405799,imis,IDEAGPRS,nil,1,nil,nil +405800,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405800,aircelwap,PocketInternet,nil,1,nil,nil +405801,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405801,aircelwap,PocketInternet,nil,1,nil,nil +405802,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405802,aircelwap,PocketInternet,nil,1,nil,nil +405803,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405803,aircelwap,PocketInternet,nil,1,nil,nil +405804,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405804,aircelwap,PocketInternet,nil,1,nil,nil +405805,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405805,aircelwap,PocketInternet,nil,1,nil,nil +405806,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405806,aircelwap,PocketInternet,nil,1,nil,nil +405807,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405807,aircelwap,PocketInternet,nil,1,nil,nil +405808,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405808,aircelwap,PocketInternet,nil,1,nil,nil +405809,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405809,aircelwap,PocketInternet,nil,1,nil,nil +405810,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405810,aircelwap,PocketInternet,nil,1,nil,nil +405811,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405811,aircelwap,PocketInternet,nil,1,nil,nil +405812,aircelgprs,Aircel-GPRS,nil,1,nil,nil +405812,aircelwap,PocketInternet,nil,1,nil,nil +405813,uninor,UninorInternet,nil,1,nil,1 +405813,uninor,UninorWap,nil,1,nil,nil +405814,uninor,UninorInternet,nil,1,nil,1 +405814,uninor,UninorWap,nil,1,nil,nil +405815,uninor,UninorInternet,nil,1,nil,1 +405815,uninor,UninorWap,nil,1,nil,nil +405816,uninor,UninorInternet,nil,1,nil,1 +405816,uninor,UninorWap,nil,1,nil,nil +405817,uninor,UninorInternet,nil,1,nil,1 +405817,uninor,UninorWap,nil,1,nil,nil +405818,uninor,UninorInternet,nil,1,nil,1 +405818,uninor,UninorWap,nil,1,nil,nil +405819,uninor,UninorInternet,nil,1,nil,1 +405819,uninor,UninorWap,nil,1,nil,nil +405820,uninor,UninorInternet,nil,1,nil,1 +405820,uninor,UninorWap,nil,1,nil,nil +405821,uninor,UninorInternet,nil,1,nil,1 +405821,uninor,UninorWap,nil,1,nil,nil +405822,uninor,UninorInternet,nil,1,nil,1 +405822,uninor,UninorWap,nil,1,nil,nil +405823,vinternet.com,Videocon,nil,1,nil,nil +405824,vinternet.com,Videocon,nil,1,nil,nil +405825,vinternet.com,Videocon,nil,1,nil,nil +405826,vinternet.com,Videocon,nil,1,nil,nil +405827,vinternet.com,Videocon,nil,1,nil,nil +405828,vinternet.com,Videocon,nil,1,nil,nil +405829,vinternet.com,Videocon,nil,1,nil,nil +405830,vinternet.com,Videocon,nil,1,nil,nil +405831,vinternet.com,Videocon,nil,1,nil,nil +405832,vinternet.com,Videocon,nil,1,nil,nil +405833,vinternet.com,Videocon,nil,1,nil,nil +405834,vinternet.com,Videocon,nil,1,nil,nil +405835,vinternet.com,Videocon,nil,1,nil,nil +405836,vinternet.com,Videocon,nil,1,nil,nil +405837,vinternet.com,Videocon,nil,1,nil,nil +405838,vinternet.com,Videocon,nil,1,nil,nil +405839,vinternet.com,Videocon,nil,1,nil,nil +405840,vinternet.com,Videocon,nil,1,nil,nil +405841,vinternet.com,Videocon,nil,1,nil,nil +405842,vinternet.com,Videocon,nil,1,nil,nil +405843,vinternet.com,Videocon,nil,1,nil,nil +405844,uninor,UninorInternet,nil,1,nil,1 +405844,uninor,UninorWap,nil,1,nil,nil +405845,internet,Idea_Internet,nil,1,nil,nil +405845,imis,IDEAGPRS,nil,1,nil,nil +405846,internet,Idea_Internet,nil,1,nil,nil +405846,imis,IDEAGPRS,nil,1,nil,nil +405847,internet,Idea_Internet,nil,1,nil,nil +405847,imis,IDEAGPRS,nil,1,nil,nil +405848,internet,Idea_Internet,nil,1,nil,nil +405848,imis,IDEAGPRS,nil,1,nil,nil +405849,internet,Idea_Internet,nil,1,nil,nil +405849,imis,IDEAGPRS,nil,1,nil,nil +405850,internet,Idea_Internet,nil,1,nil,nil +405850,imis,IDEAGPRS,nil,1,nil,nil +405851,internet,Idea_Internet,nil,1,nil,nil +405851,imis,IDEAGPRS,nil,1,nil,nil +405852,internet,Idea_Internet,nil,1,nil,nil +405852,imis,IDEAGPRS,nil,1,nil,nil +405853,internet,Idea_Internet,nil,1,nil,nil +405853,imis,IDEAGPRS,nil,1,nil,nil +405854,www,LoopInternet(405854),nil,1,nil,nil +405855,www,LoopInternet(405855),nil,1,nil,nil +405856,www,LoopInternet(405856),nil,1,nil,nil +405857,www,LoopInternet(405857),nil,1,nil,nil +405858,www,LoopInternet(405858),nil,1,nil,nil +405859,www,LoopInternet(405859),nil,1,nil,nil +405860,www,LoopInternet(405860),nil,1,nil,nil +405861,www,LoopInternet(405861),nil,1,nil,nil +405862,www,LoopInternet(405862),nil,1,nil,nil +405863,www,LoopInternet(405863),nil,1,nil,nil +405864,www,LoopInternet(405864),nil,1,nil,nil +405865,www,LoopInternet(405865),nil,1,nil,nil +405866,www,LoopInternet(405866),nil,1,nil,nil +405867,www,LoopInternet(405867),nil,1,nil,nil +405868,www,LoopInternet(405868),nil,1,nil,nil +405869,www,LoopInternet(405869),nil,1,nil,nil +405870,www,LoopInternet(405870),nil,1,nil,nil +405871,www,LoopInternet(405871),nil,1,nil,nil +405872,www,LoopInternet(405872),nil,1,nil,nil +405873,www,LoopInternet(405873),nil,1,nil,nil +405874,www,LoopInternet(405874),nil,1,nil,nil +405875,uninor,UninorInternet,nil,1,nil,1 +405875,uninor,UninorWap,nil,1,nil,nil +405876,uninor,UninorInternet,nil,1,nil,1 +405876,uninor,UninorWap,nil,1,nil,nil +405877,uninor,UninorInternet,nil,1,nil,1 +405877,uninor,UninorWap,nil,1,nil,nil +405878,uninor,UninorInternet,nil,1,nil,1 +405878,uninor,UninorWap,nil,1,nil,nil +405879,uninor,UninorInternet,nil,1,nil,1 +405879,uninor,UninorWap,nil,1,nil,nil +405880,uninor,UninorInternet,nil,1,nil,1 +405880,uninor,UninorWap,nil,1,nil,nil +405881,gprs.stel.in,STEL,nil,1,nil,nil +405882,gprs.stel.in,STEL,nil,1,nil,nil +405883,gprs.stel.in,STEL,nil,1,nil,nil +405884,gprs.stel.in,STEL,nil,1,nil,nil +405885,gprs.stel.in,STEL,nil,1,nil,nil +405886,gprs.stel.in,STEL,nil,1,nil,nil +405908,internet,IDEA,nil,1,nil,nil +405909,internet,IDEA,nil,1,nil,nil +405910,internet,IDEA,nil,1,nil,nil +405911,internet,IDEA,nil,1,nil,nil +405912,internet,Cheers,nil,1,nil,nil +405913,internet,Cheers,nil,1,nil,nil +405914,internet,Cheers,nil,1,nil,nil +405915,internet,Cheers,nil,1,nil,nil +405916,internet,Cheers,nil,1,nil,nil +405917,internet,Cheers,nil,1,nil,nil +405918,internet,Cheers,nil,1,nil,nil +405919,internet,Cheers,nil,1,nil,nil +405920,internet,Cheers,nil,1,nil,nil +405921,internet,Cheers,nil,1,nil,nil +405922,internet,Cheers,nil,1,nil,nil +405923,internet,Cheers,nil,1,nil,nil +405924,internet,Cheers,nil,1,nil,nil +405925,uninor,UninorInternet,nil,1,nil,1 +405925,uninor,UninorWap,nil,1,nil,nil +405926,uninor,UninorInternet,nil,1,nil,1 +405926,uninor,UninorWap,nil,1,nil,nil +405927,uninor,UninorInternet,nil,1,nil,1 +405927,uninor,UninorWap,nil,1,nil,nil +405928,uninor,UninorInternet,nil,1,nil,1 +405928,uninor,UninorWap,nil,1,nil,nil +405929,uninor,UninorInternet,nil,1,nil,1 +405929,uninor,UninorWap,nil,1,nil,nil +405930,internet,Cheers,nil,1,nil,nil +405931,internet,Cheers,nil,1,nil,nil +405932,vinternet.com,Videocon,nil,1,nil,nil +41001,connect.mobilinkworld.com,MobilinkWAPGPRS,Mobilink,1,Mobilink,nil +41003,Ufone.internet,UfoneWAP,nil,1,nil,nil +41004,zonginternet,ZONGWAP,nil,1,nil,nil +41006,internet,TelenorWAP,nil,1,nil,nil +41007,Wap.warid,WaridWAP,nil,1,nil,nil +410310,att.mvno,ConsumerCellular,nil,1,nil,nil +41201,default,AWCC,nil,1,nil,nil +41220,default,Roshan,nil,1,nil,nil +41240,default,MTN,nil,1,nil,nil +41250,default,Etisalat,nil,1,nil,nil +41301,default,Mobitel,nil,1,nil,nil +41302,default,Dialog,nil,1,nil,nil +41303,default,Etisalat,nil,1,nil,nil +41305,default,Airtel,nil,1,nil,nil +41308,default,Hutch,nil,1,nil,nil +41401,default,MPT,nil,1,nil,nil +41405,Internet,OoredooInternet,nil,1,nil,nil +41501,internet.mic1.com.lb,AlfaInternet,mic1,1,mic1,nil +41501,wap.mic1.com.lb,Alfawap,mic1,1,mic1,nil +41503,touch,touch,nil,1,nil,nil +41503,wap,touch_WAP,nil,1,nil,nil +41601,zain,ZainJOInternet,zain,1,zain,1 +41601,Zain,ZainJOStreaming,zain,1,zain,1 +41603,net,Umniahinternet,nil,1,nil,nil +41603,wap,UmniahWAP,nil,1,nil,nil +416770,net.orange.jo,OrangeInternet,net,1,net,1 +416770,wap.orange.jo,OrangeWAP,wap,1,wap,1 +41677,net.orange.jo,OrangeInternet,net,1,net,1 +41677,wap.orange.jo,OrangeWAP,wap,1,wap,1 +41701,net.syriatel.com,SyriatelNet,nil,1,nil,nil +41702,internet,MTNWAP,nil,1,nil,nil +41805,net.asiacell.com,AsiacellInternet,nil,1,nil,nil +41808,default,SanaTel,nil,1,nil,nil +41820,internet,ZAIN-GPRS,atheer,1,atheer,1 +41830,internet,ZAIN-GPRS,atheer,1,atheer,1 +41840,internet.korek.com,Korek9595,nil,1,nil,nil +41840,net.korek.com,Korek9191,korek,1,korek,nil +41845,default,Mobitel,nil,1,nil,nil +41862,default,Itisaluna,nil,1,nil,nil +41892,default,Omnnea,nil,1,nil,nil +41902,pps,MI,pps,1,pps,nil +41902,pps,ZainWAP,pps,1,pps,3 +41903,action.ooredoo.com,OoredooAction,nil,1,nil,1 +41903,mms.ooredoo.com,OoredooMMS,nil,1,nil,1 +41904,viva,VIVA-KW,nil,1,nil,0 +42001,jawalnet.com.sa,STC-GPRS,nil,1,nil,nil +42003,web1,MobilyWEB,nil,1,nil,nil +42003,wap2,Mobilyprepaid-GPRS,nil,1,nil,nil +42003,wap1,Mobilypostpaid-GPRS,nil,1,nil,nil +42003,web2,MobilyWEB2,nil,1,nil,nil +42004,zain,zain-InternetWap,nil,1,nil,0 +42101,default,SabaFon,nil,1,nil,nil +42102,default,MTN,nil,1,nil,nil +42103,default,YemenMobile,nil,1,nil,nil +42104,default,HiTS-UNITEL,nil,1,nil,nil +42202,taif,OmanMobileInternet,taif,1,taif,1 +42203,isp.nawras.com.om,NawrasInternet,test,1,test,1 +42402,etisalat.ae,EtisalatDataPackage,nil,1,nil,1 +42402,etisalat,WeyakWap,nil,1,nil,1 +42403,du,duInternet,nil,1,nil,nil +42501,uwap.orange.co.il,3GPortal,nil,1,nil,nil +42502,sphone,CellcomInternet,nil,1,nil,nil +42503,sphone.pelephone.net.il,SphonePelephone,pcl,1,pcl@3g,2 +42505,wap,JawwalWAP,nil,1,nil,nil +42506,internet,Internet,nil,1,nil,nil +42507,net.hotm,InternetHOTmobile,nil,1,nil,nil +42507,pc.hotm,PCHOTmobile,nil,1,nil,0 +42508,internet.golantelecom.net.il,GolanTelecomInternet,nil,1,nil,nil +42510,uwap.orange.co.il,3GPortal,nil,1,nil,nil +42514,data.youphone.co.il,YouPhone,nil,1,nil,nil +42515,hcminternet,HomeCellularInternet,nil,1,nil,nil +42516,internet.rl,RamiLevi3G,nil,1,nil,nil +42601,internet.batelco.com,BatelcoInternet,nil,1,nil,nil +42601,wap.batelco.com,BatelcoWAP,wap,1,wap,0 +42602,internet,ZainBHInternet,internet,1,internet,0 +42602,wap,ZainBHWAP,wap,1,wap,0 +42604,viva.bh,VIVAGPRS,nil,1,nil,nil +42604,vivawap.bh,VIVAWAP,nil,1,nil,nil +42701,data,Internet,nil,1,nil,1 +42702,web.vodafone.com.qa,Vodainternet,nil,1,nil,nil +42888,default,Unitel,nil,1,nil,nil +42891,default,Skytel,nil,1,nil,nil +42898,default,G.Mobile,nil,1,nil,nil +42899,default,MobiCom,nil,1,nil,nil +42901,default,Namaste/NTMobile,nil,1,nil,nil +42902,default,Ncell,nil,1,nil,nil +42903,default,Sky/C-Phone,nil,1,nil,nil +42904,default,SmartCell,nil,1,nil,nil +43211,mcinet,MCI-GPRS,nil,1,nil,nil +43214,mcinet,MCI-GPRS,nil,1,nil,nil +43219,mcinet,MCI-GPRS,nil,1,nil,nil +43220,rightel,rightel,nil,1,nil,nil +43235,mtnirancell,Irancell-GPRS,nil,1,nil,nil +43270,mcinet,MCI-GPRS,nil,1,nil,nil +43293,mcinet,MCI-GPRS,nil,1,nil,nil +43404,internet.beeline.uz,Beeline-UZBInternet,beeline,1,beeline,1 +43405,internet,UCELLInternet,nil,1,nil,nil +43406,default,PerfectumMobile,nil,1,nil,nil +43407,net.mts.uz,MTS-UZBInternet,mts,1,mts,1 +43601,default,Tcell,nil,1,nil,nil +43602,default,Tcell,nil,1,nil,nil +43603,default,Megafon,nil,1,nil,nil +43604,default,Babilon-M,nil,1,nil,nil +43605,default,Tacom,nil,1,nil,nil +43612,default,Tcell,nil,1,nil,nil +43701,default,Beeline,nil,1,nil,nil +43703,default,Fonex,nil,1,nil,nil +43705,default,MegaCom,nil,1,nil,nil +43709,default,O!,nil,1,nil,nil +43801,default,MTS(BARASHCommunication),nil,1,nil,nil +43802,default,TM-Cell,nil,1,nil,nil +44003,iijmio.jp,IIJmio(TypeI),iij,1,mio@iij,3 +44003,vmobile.jp,vmobile.jp,vmobile,1,vmobile@jp,3 +44010,spmode.ne.jp,sp-mode,nil,1,nil,nil +44010,mopera.net,moperaU,nil,1,nil,nil +44010,bmobile.ne.jp,b-mobileforNexus,bmobile,1,bmobile@nx,3 +44010,iijmio.jp,IIJmio,iij,1,mio@iij,3 +44010,3g-d-2.ocn.ne.jp,OCNモãƒã‚¤ãƒ«ONE(3G),mobile,1,mobileid@ocn,2 +44010,lte-d.ocn.ne.jp,OCNモãƒã‚¤ãƒ«ONE(LTE),mobile,1,mobileid@ocn,2 +44010,ratel.com,RATEL,ratel,1,ratel@ratel.com,3 +44020,plus.acs.jp,Application,ym,1,ym,2 +44020,ratel.com,RATEL,ratel,1,ratel@ratel.com,3 +44051,ratel.com,RATEL,ratel,1,ratel@ratel.com,3 +44051,a.rmobile.jp,Rakuten,0000,1,rakuten@vdm,3 +45005,lte.sktelecom.com,SKTLTEINTERNET,nil,1,nil,nil +45005,web.sktelecom.com,SKT3GINTERNET,nil,1,nil,nil +45005,lte-roaming.sktelecom.com,SKTLTERoaming,nil,1,nil,nil +45005,roaming.sktelecom.com,SKT3GRoaming,nil,1,nil,nil +45011,web.sktelecom.com,SKT3GINTERNET,nil,1,nil,nil +45011,lte-roaming.sktelecom.com,SKTLTERoaming,nil,1,nil,nil +45011,roaming.sktelecom.com,SKT3GRoaming,nil,1,nil,nil +45006,internet.lguplus.co.kr,LGuplus,nil,1,nil,nil +45006,lte-roaming.lguplus.co.kr,LGuplusLTERoaming,nil,1,nil,0 +45006,wroaming.lguplus.co.kr,LGuplusRoaming,nil,1,nil,0 +45008,lte.ktfwing.com,KT,nil,1,nil,nil +45201,m-wap,Mobi-wap-gprs2,mms,1,mms,1 +45202,m3-world,Vina-wap-gprs,mms,1,mms,1 +45204,v-internet,Viettel-wap-gprs1,nil,1,nil,nil +45204,v-wap,Viettel-wap-gprs2,nil,1,nil,nil +45205,internet,Vietnamobile_GPRS3,nil,1,nil,nil +45205,wap,Vietnamobile_GPRS1,nil,1,nil,nil +45207,internet,Gmobile-wap-gprs2,nil,1,nil,nil +45208,e-internet,e-internet,nil,1,nil,nil +45208,e-wap,e-wap,nil,1,nil,nil +45400,mobile,1O1O,nil,1,nil,3 +45400,NWMOBILE,NWMOBILE,nil,1,nil,3 +45402,mobile,1O1O,nil,1,nil,3 +45402,NWMOBILE,NWMOBILE,nil,1,nil,3 +45403,mobile.lte.three.com.hk,3LTE,nil,1,nil,1 +45403,mobile.three.com.hk,3,nil,1,nil,1 +45404,web-g.three.com.hk,3(2G)GPRS,nil,1,nil,nil +45406,SmarTone,SmarTone,nil,1,nil,3 +45408,iot.truphone.com,Truphone,nil,1,nil,nil +45410,hkcsl,one2free,nil,1,nil,3 +45412,cmhk,CMHKData,nil,1,nil,nil +45413,cmhk,CMHKData,nil,1,nil,nil +45415,SmarTone,SmarTone,nil,1,nil,3 +45416,pccw,PCCW-HKT,nil,1,nil,1 +45417,SmarTone,SmarTone,nil,1,nil,3 +45418,mobile,1O1O,nil,1,nil,3 +45418,NWMOBILE,NWMOBILE,nil,1,nil,3 +45419,pccw,PCCW-HKT,nil,1,nil,1 +45500,smartgprs,SmarToneMacau,nil,1,nil,3 +45501,ctm-mobile,CTMData,nil,1,nil,nil +45501,ctmprepaid,CTM(Prepaid),nil,1,nil,nil +45503,mobile.three.com.mo,3Macau,nil,1,nil,1 +45504,ctm-mobile,CTMData,nil,1,nil,nil +45504,ctmprepaid,CTM(Prepaid),nil,1,nil,nil +45505,mobile.three.com.mo,3Macau,nil,1,nil,1 +45601,default,Cellcard,nil,1,nil,nil +45602,default,Smart,nil,1,nil,nil +45604,default,qb,nil,1,nil,nil +45605,default,Star-Cell,nil,1,nil,nil +45606,default,Smart,nil,1,nil,nil +45608,default,Metfone,nil,1,nil,nil +45609,default,Beeline,nil,1,nil,nil +45611,default,Excell,nil,1,nil,nil +45618,default,Cellcard,nil,1,nil,nil +45701,default,LTC,nil,1,nil,nil +45702,default,ETL,nil,1,nil,nil +45703,default,Unitel,nil,1,nil,nil +45708,default,Beeline,nil,1,nil,nil +46000,cmnet,中国移动(ChinaMobile)GPRS,nil,1,nil,nil +46000,cmwap,中国移动(ChinaMobile)WAP,nil,1,nil,nil +46001,3gnet,沃3G连接互è”网(ChinaUnicom),nil,1,nil,nil +46001,3gwap,沃3G手机上网(ChinaUnicom),nil,1,nil,nil +46001,uninet,è”通2GNET上网(ChinaUnicom),nil,1,nil,nil +46002,cmnet,中国移动(ChinaMobile)GPRS,nil,1,nil,nil +46002,cmwap,中国移动(ChinaMobile)WAP,nil,1,nil,nil +46007,cmnet,中国移动(ChinaMobile)GPRS,nil,1,nil,nil +46008,cmnet,中国移动(ChinaMobile)GPRS,nil,1,nil,nil +46007,cmwap,中国移动(ChinaMobile)WAP,nil,1,nil,nil +46008,cmwap,中国移动(ChinaMobile)WAP,nil,1,nil,nil +46009,3gnet,ChinaUnicom3G,nil,1,nil,nil +46009,3gwap,ChinaUnicomwap,nil,1,nil,nil +46011,ctlte,ctlte,nil,1,nil,0 +46003,ctnet,CTNET,vnet.mobi,1,ctnet@mycdma.cn,3 +46003,ctwap,CTWAP,vnet.mobi,1,ctwap@mycdma.cn,3 +20404,ctnet,CTNET,nil,1,nil,0 +46601,internet,é å‚³é›»ä¿¡(FarEasTone)(Internet),nil,1,nil,nil +46688,internet,和信電訊(KGT-Online)(Internet),nil,1,nil,nil +46689,vibo,VIBO-vibo,nil,1,nil,nil +46689,internet,TStar-internet,nil,1,nil,nil +46689,viboone,VIBOONE,nil,1,nil,nil +46692,internet,中è¯é›»ä¿¡(Chunghwa)(Internet),nil,1,nil,nil +46693,Internet,å°ç£å¤§å“¥å¤§(TWMobile)(Internet),nil,1,nil,nil +46697,Internet,å°ç£å¤§å“¥å¤§(TWMobile)(Internet),nil,1,nil,nil +46699,Internet,å°ç£å¤§å“¥å¤§(TWMobile)(Internet),nil,1,nil,nil +47001,gpinternet,GP-INTERNET,nil,1,nil,0 +47201,default,Dhiraagu,nil,1,nil,nil +47202,OoredooData,OoredooData,nil,1,nil,nil +50210,diginet,DiGiInternet,nil,1,nil,nil +50212,max4g,MaxisInternet,wap,1,maxis,1 +50213,celcom4g,CelcomInternet,nil,1,nil,nil +502143,diginet,DiGiInternet,nil,1,nil,nil +502145,celcom4g,CelcomInternet,nil,1,nil,nil +502146,diginet,DiGiInternet,nil,1,nil,nil +502148,celcom4g,CelcomInternet,nil,1,nil,nil +50216,diginet,DiGiInternet,nil,1,nil,nil +50217,max4g,MaxisInternet,wap,1,maxis,1 +50218,my3g,UMobileInternet,nil,1,nil,nil +50219,celcom4g,CelcomInternet,nil,1,nil,nil +50501,telstra.wap,TelstraInternet,nil,1,nil,nil +50501,telstra.internet,TelstraTethering,nil,1,nil,nil +50502,yesinternet,OptusYesInternet,nil,1,nil,nil +50503,live.vodafone.com,Vodafonelive!,nil,1,nil,nil +50506,3services,Planet3,nil,1,nil,0 +50507,vfinternet.au,VFInternet,nil,1,nil,nil +50511,Telstra.wap,TelstraInternet,nil,1,nil,nil +50512,3netaccess,3Internet,nil,1,nil,nil +50512,3services,3,nil,1,nil,nil +50538,iot.truphone.com,Truphone,nil,1,nil,nil +50571,Telstra.wap,TelstraInternet,nil,1,nil,nil +50572,Telstra.wap,TelstraInternet,nil,1,nil,nil +50588,vfinternet.au,VFInternet,nil,1,nil,nil +50590,internet,OptusInternet,nil,1,nil,nil +50599,live.vodafone.com,VodafoneLive!,nil,1,nil,nil +51001,indosatgprs,indosatgprs,nil,1,nil,1 +51008,AXIS,AXIS-SNS,nil,1,nil,1 +51008,AXIS,AXISwap,123456,1,axis,1 +51010,internet,internet,nil,1,nil,nil +51010,telkomsel,TSEL-WAP,wap123,1,wap,1 +51011,internet,Internet,nil,1,nil,1 +51021,indosatgprs,Indosat-SNS,nil,1,nil,1 +51021,indosatgprs,IndosatGPRS,indosat,1,indosat,1 +51089,3gprs,3-SNS,nil,1,nil,1 +51089,3gprs,3GPRS,3gprs,1,3gprs,1 +51401,default,Telin,nil,1,nil,nil +51402,default,TimorTelecom,nil,1,nil,nil +51403,default,ViettelTimor-Leste,nil,1,nil,nil +51502,internet.globe.com.ph,myGlobeInternet,nil,1,nil,nil +51502,http.globe.com.ph,myGlobeINET,nil,1,nil,nil +51502,www.globe.com.ph,myGlobeConnect,nil,1,nil,nil +51503,smartlte,SMARTLTE,nil,1,nil,nil +51503,internet,SMARTINTERNET,nil,1,nil,nil +51503,Smart1,SmartGPRS,nil,1,nil,nil +51505,minternet,SunInternet,nil,1,nil,nil +51505,wap,SUNWAPGPRS,nil,1,nil,nil +51505,fbband,SunSBW,nil,1,nil,nil +51518,redinternet,Redinternet,nil,1,nil,nil +52000,internet,CAT3GINTERNET,nil,1,nil,nil +52000,internet,TRUE-HINTERNET,true,1,true,1 +52001,internet,AISInternet,nil,1,nil,0 +52003,internet,AISInternet,nil,1,nil,0 +52004,internet,TRUE-HINTERNET,true,1,true,1 +52005,www.dtac.co.th,dtacInternet,nil,1,nil,nil +52015,internet,TOT3GInternet,nil,1,nil,nil +52018,www.dtac.co.th,dtacInternet,nil,1,nil,nil +52099,internet,TRUEINTERNET,true,1,true,1 +52501,e-ideas,SingTel(PostPaid),nil,1,nil,nil +52501,hicard,SingTel(PrePaid),nil,1,nil,nil +52502,e-ideas,SingTel(PostPaid),nil,1,nil,nil +52502,hicard,SingTel(PrePaid),nil,1,nil,nil +52503,sunsurf,SunsurfMobile,nil,1,nil,nil +52504,sunsurf,SunsurfMobile,nil,1,nil,nil +52505,shwap,SHDataPostpaid,nil,1,nil,nil +52802,default,B-Mobile,nil,1,nil,nil +52811,default,DSTCom,nil,1,nil,nil +53001,vodafone,VFNZInternet,nil,1,nil,nil +53005,Internet,Data,nil,1,nil,nil +53005,wapaccess.co.nz,Default,nil,1,nil,nil +53024,internet,2DegreesInternet,nil,1,nil,nil +53602,default,Digicel,nil,1,nil,nil +53701,default,BeMobile,nil,1,nil,nil +53703,wap.digicelpng.com,PNGWAP,nil,1,nil,nil +53703,internet.digicelpng.com,PNGWEB,nil,1,nil,nil +53703,wap.digicel.com.pg,PapuaNewGuinea,nil,1,nil,1 +53703,em,EMnify,nil,1,nil,nil +53901,default,U-Call,nil,1,nil,nil +53943,default,ShorelineCommunication,nil,1,nil,nil +53988,default,Digicel,nil,1,nil,nil +53988,wap,Tonga,nil,1,nil,1 +54001,default,BREEZE,nil,1,nil,nil +54002,default,BeMobile,nil,1,nil,nil +54100,default,AIL,nil,1,nil,nil +54101,default,SMILE,nil,1,nil,nil +54105,default,Digicel,nil,1,nil,nil +54105,wap,Vanatu,nil,1,nil,1 +54201,default,Vodafone,nil,1,nil,nil +54202,default,Digicel,nil,1,nil,nil +54202,wap,Fiji,nil,1,nil,1 +54411,default,Bluesky,nil,1,nil,nil +54501,default,Kiribati-TSKL,nil,1,nil,nil +54509,default,Kiribati-FrigateNet,nil,1,nil,nil +54601,default,Mobilis,nil,1,nil,nil +54720,default,Vini,nil,1,nil,nil +54801,default,TelecomCook,nil,1,nil,nil +54901,default,Digicel,nil,1,nil,nil +54927,default,Bluesky,nil,1,nil,nil +55001,default,FSMTC,nil,1,nil,nil +55101,default,MINTA,nil,1,nil,nil +55201,default,PNCC,nil,1,nil,nil +55280,default,PalauMobile,nil,1,nil,nil +60201,mobinilweb,MobinilWeb,nil,1,nil,nil +60201,mobinilwap,MobinilWAP,nil,1,nil,nil +60202,internet.vodafone.net,vodafoneinternet,internet,1,internet,3 +60202,wap.vodafone.com.eg,VodafoneWAP,wap,1,wap,3 +60203,etisalat,EtisalatWAP,nil,1,nil,nil +60301,wap,mobiliswap,wap,1,wap,1 +60301,internet,Mobilisinternet,internet,1,internet,1 +60302,djezzy.internet,djezzy.internet,nil,1,nil,nil +60303,internet,Ooredoointernet,nil,1,nil,1 +60400,internet.orange.ma,Internet,nil,1,nil,1 +60400,wap.meditel.ma,Imedia,MEDIWAP,1,MEDIWAP,1 +60401,wap.iamgprs.ma,MobileZone,nil,1,nil,nil +60401,www.iamgprs1.ma,InternetMobile,nil,1,nil,nil +60402,www.wana.ma,WEB,nil,1,nil,nil +60501,weborange,weborange,nil,1,nil,nil +60502,internet.tn,Internet,nil,1,nil,nil +60502,gprs.tn,InternetPortail,gprs,1,gprs,1 +60503,internet.ooredoo.tn,OoredooTNInternet,nil,1,nil,nil +60600,default,Libyana,nil,1,nil,nil +60601,default,Madar,nil,1,nil,nil +60602,default,Al-JeelPhone,nil,1,nil,nil +60603,default,LibyaPhone,nil,1,nil,nil +60606,default,HatefLibya,nil,1,nil,nil +60701,default,Gamcel,nil,1,nil,nil +60702,default,Africel,nil,1,nil,nil +60703,default,Comium,nil,1,nil,nil +60704,default,QCell,nil,1,nil,nil +60801,wap,OrangeWapSN,wap,1,wap,nil +60801,internet,OrangeWebSN,internet,1,internet,nil +60802,web.sentel.com,TigoInternetSN,nil,1,nil,nil +60803,expresso,ExpressoInternetSN,wap,1,wap,nil +60901,default,Mattel,nil,1,nil,nil +60902,default,Chinguitel,nil,1,nil,nil +60910,default,Mauritel,nil,1,nil,nil +61002,internet,Orange3G/4G,internet,1,internet,1 +61002,wap,OrangeWapML,wap,1,wap,nil +61101,default,OrangeS.A.,nil,1,nil,nil +61102,default,Sotelgui,nil,1,nil,nil +61103,default,TelecelGuinee,nil,1,nil,nil +61104,default,MTN,nil,1,nil,nil +61105,default,Cellcom,nil,1,nil,nil +61202,moov,MoovInternetCI,web,1,web,nil +61203,orangeciweb,Oweb,web,1,web,1 +61203,orangeciwap,OWORLDCI,wap,1,wap,nil +61204,gprs.koz.ci,KozInternetCI,web,1,web,nil +61205,web.mtn.ci,MTNInternetCI,vide,1,vide,nil +61301,default,Telmob,nil,1,nil,nil +61302,default,Airtel,nil,1,nil,nil +61303,default,TelecelFaso,nil,1,nil,nil +61404,orange.ne,OrangeInternet,nil,1,nil,nil +61501,default,TogoCell,nil,1,nil,nil +61503,default,Moov,nil,1,nil,nil +61601,default,Libercom,nil,1,nil,nil +61602,default,Moov,nil,1,nil,nil +61603,default,MTN,nil,1,nil,nil +61604,default,BBCOM,nil,1,nil,nil +61605,default,Glo,nil,1,nil,nil +61701,orange,OrangeInternet,nil,1,nil,nil +61801,default,LonestarCell,nil,1,nil,nil +61802,default,Libercell,nil,1,nil,nil +61804,default,Comium,nil,1,nil,nil +61807,Orange,Orange,nil,1,nil,nil +61820,default,LIBTELCO,nil,1,nil,nil +61901,default,Airtel,nil,1,nil,nil +61902,default,Tigo,nil,1,nil,nil +61903,default,Africell,nil,1,nil,nil +61904,default,Comium,nil,1,nil,nil +61905,default,Africell,nil,1,nil,nil +61925,default,Mobitel,nil,1,nil,nil +6200,glowap,Glo,nil,1,nil,0 +62001,internet,MTNInternetGH,nil,1,nil,nil +62002,browse,VodafoneInternetGH,nil,1,nil,nil +62003,web.tigo.com.gh,TigoInternetGH,nil,1,nil,nil +62006,wap,AirtelInternetGH,nil,1,nil,nil +62007,glowap,GloInternetGH,glo,1,glo,1 +62120,internet.ng.zain.com,AirtelInternet,internet,1,internet,1 +62120,wap.ng.zain.com,AirtelWAP,wap,1,wap,1 +62130,web.gprs.mtnnigeria.net,MTNWAP,web,1,web,1 +62150,glosecure,GloDirect,gprs,1,gprs,1 +62160,etisalat,etisalatWAP,nil,1,nil,nil +62201,default,Airtel,nil,1,nil,nil +62202,default,Tawali,nil,1,nil,nil +62203,default,Tigo,nil,1,nil,nil +62204,default,Salam,nil,1,nil,nil +62301,default,CTP,nil,1,nil,nil +62302,default,TC,nil,1,nil,nil +62303,orangeca3g,Internetbrowsing,nil,1,nil,nil +62304,default,Nationlink,nil,1,nil,nil +62501,default,CVMOVEL,nil,1,nil,nil +62502,default,T+,nil,1,nil,nil +62601,default,CSTmovel,nil,1,nil,nil +62701,default,OrangeGQ,nil,1,nil,nil +62703,default,HitsGQ,nil,1,nil,nil +62801,default,Libertis,nil,1,nil,nil +62802,default,Moov,nil,1,nil,nil +62803,default,Airtel,nil,1,nil,nil +62804,default,Azur,nil,1,nil,nil +62901,default,Airtel,nil,1,nil,nil +62910,default,LibertisTelecom,nil,1,nil,nil +63001,vodanet,VodacomInternetCD,nil,1,nil,nil +63089,tigo.web,TigoInternetCD,nil,1,nil,nil +63102,default,UNITEL,nil,1,nil,nil +63104,default,MOVICEL,nil,1,nil,nil +63202,default,Areeba,nil,1,nil,nil +63203,4Gogb,OrangeBissau,nil,1,nil,nil +63207,default,Guinetel,nil,1,nil,nil +63301,default,Cable&Wireless,nil,1,nil,nil +63302,default,MediatechInternational,nil,1,nil,nil +63310,default,Airtel,nil,1,nil,nil +63401,default,ZainSD,nil,1,nil,nil +63402,default,MTN,nil,1,nil,nil +63407,default,SudaniOne,nil,1,nil,nil +63409,default,PrivetNetwork,nil,1,nil,nil +63510,default,MTN,nil,1,nil,nil +63512,default,Rwandatel,nil,1,nil,nil +63513,default,Tigo,nil,1,nil,nil +63514,default,Airtel,nil,1,nil,nil +63601,default,ETH-MTN,nil,1,nil,nil +63701,default,Telesom,nil,1,nil,nil +63704,default,Somafone,nil,1,nil,nil +63710,default,Nationlink,nil,1,nil,nil +63725,default,Hormuud,nil,1,nil,nil +63730,default,Golis,nil,1,nil,nil +63757,default,Unittel,nil,1,nil,nil +63760,default,NationlinkTelecom,nil,1,nil,nil +63771,default,Somtel,nil,1,nil,nil +63782,default,Telcom,nil,1,nil,nil +63801,default,Evatis,nil,1,nil,nil +63902,safaricom,safaricomGPRS,data,1,saf,1 +63903,internet,AirtelInternet,nil,1,nil,nil +63903,ke.celtel.com,Airtel,nil,1,nil,nil +63905,Internet,YuInternet,nil,1,nil,nil +63905,Yuinternet,YuWAP,nil,1,nil,nil +63907,bew.orange.co.ke,OrangeInternet,nil,1,nil,nil +64004,Wap,VodacomWAP,nil,1,nil,nil +64101,internet,AirtelInternetUG,nil,1,nil,nil +64110,yellopix.mtn.co.ug,MTNInternetUG,nil,1,nil,nil +64111,utweb,UTLInternetUG,nil,1,nil,nil +64114,orange.ug,OrangeInternetUG,nil,1,nil,nil +64122,web.waridtel.co.ug,WaridTelecomInternetUG,nil,1,nil,nil +64201,default,Spacetel,nil,1,nil,nil +64202,default,Tempo,nil,1,nil,nil +64203,default,Onatel,nil,1,nil,nil +64207,default,SmartMobile,nil,1,nil,nil +64208,default,HiTsTelecom,nil,1,nil,nil +64282,default,Leo,nil,1,nil,nil +64301,default,mCel,nil,1,nil,nil +64303,default,Movitel,nil,1,nil,nil +64304,default,Vodacom,nil,1,nil,nil +64501,default,Airtel,nil,1,nil,nil +64502,default,MTN,nil,1,nil,nil +64503,default,ZAMTEL,nil,1,nil,nil +64602,orangenet,OrangeMGInternet,nil,1,nil,0 +64700,orangerun,OrangeWorldre,orange,1,orange,nil +64702,onlywap,OnlyWap,only,1,only,1 +64703,free.re,FreeRe,nil,1,nil,nil +64710,sl2sfr,FullInternetSRR,nil,1,nil,nil +64710,wapsfr,GPRSSRR,wap,1,wap,nil +64710,fnetcoriolis,CoriolisWAP,nil,1,nil,nil +64803,default,Telecel,nil,1,nil,nil +64804,default,Econet,nil,1,nil,nil +64901,default,MTC,nil,1,nil,nil +64902,default,switch,nil,1,nil,nil +64903,default,Leo,nil,1,nil,nil +65001,default,TNM,nil,1,nil,nil +65010,default,Airtel,nil,1,nil,nil +65101,internet,VCLInternetGPRS,nil,1,nil,nil +65310,default,SwaziMTN,nil,1,nil,nil +65401,default,HURI-SNPT,nil,1,nil,nil +65501,lte.vodacom.za,LTE.Vodacom,nil,1,nil,nil +65501,internet,Smart.Vodacom,nil,1,nil,nil +65502,internet,TelkomMobileInternet,nil,1,nil,nil +65507,internet,CellCGPRS,nil,1,nil,nil +65507,vdata,VIRGIN_INTERNET_1,nil,1,nil,nil +65510,myMTN,MTNGPRS,mtnwap,1,mtnwap,1 +65701,default,Eritel,nil,1,nil,nil +70267,default,DigiCell,nil,1,nil,nil +70299,default,Smart,nil,1,nil,nil +70401,internet.ideasclaro,InternetCLARO,nil,1,nil,nil +70402,broadband.tigo.gt,BroadbandTIGO,nil,1,nil,nil +70403,internet.movistar.gt,MovistarINTERNET,movistargt,1,movistargt,1 +704030,internet.movistar.gt,MovistarINTERNET,movistargt,1,movistargt,1 +70601,internet.ideasclaro,InternetCLARO,nil,1,nil,nil +70602,web.digicelsv.com,DigicelInternet,nil,1,nil,nil +70603,internet.tigo.sv,InternetTigo,nil,1,nil,nil +70604,internet.movistar.sv,MovistarINTERNET,movistarsv,1,movistarsv,1 +706040,internet.movistar.sv,MovistarINTERNET,movistarsv,1,movistarsv,1 +708001,internet.ideasclaro,InternetClaro,nil,1,nil,nil +70802,internet.tigo.hn,INTERNETTIGO,nil,1,nil,nil +70804,web.digicelhn.com,Honduras,nil,1,nil,1 +70804,wap.digicelhn.com,Honduras,nil,1,nil,1 +708020,internet.tigo.hn,INTERNETTIGO,nil,1,nil,nil +708040,web.digicelhn.com,Honduras,nil,1,nil,1 +71021,internet.ideasalo.ni,EnitelWEB,internet,1,internet,1 +71030,internet.movistar.ni,MovistarINTERNET,movistarni,1,movistarni,1 +710300,internet.movistar.ni,MovistarINTERNET,movistarni,1,movistarni,1 +71073,internet.ideasalo.ni,EnitelWEB,internet,1,internet,1 +710730,internet.ideasalo.ni,EnitelWEB,internet,1,internet,1 +71201,kolbi3g,KOLBI3G,nil,1,nil,nil +71201,kolbi,CostarRica,nil,1,nil,1 +71202,kolbi3g,KOLBI3G,nil,1,nil,nil +71203,internet.ideasclaro,InternetCLAROCR,nil,1,nil,nil +71204,internet.movistar.cr,MovistarINTERNET,movistarcr,1,movistarcr,1 +712019,tm7datos,InternetTuyo,nil,1,nil,nil +712190,tm7datos,InternetTuyo,nil,1,nil,nil +71220,datos.fullmovil.cr,InternetFullmovil,nil,1,nil,nil +71401,apn01.cwpanama.com.pa,Internet,nil,1,nil,nil +71402,internet.movistar.pa,MovistarINTERNET,movistarpa,1,movistarpa,1 +714020,internet.movistar.pa,MovistarINTERNET,movistarpa,1,movistarpa,1 +71403,web.claro.com.pa,WEBClaro,CLAROWEB,1,CLAROWEB,1 +71404,web.digicelpanama.com,DigicelInternet,nil,1,nil,nil +714040,web.digicelpanama.com,Panama,nil,1,nil,1 +71606,movistar.pe,MovistarINTERNET,movistar,1,movistar@datos,1 +71610,claro.pe,CLARODATOS,claro,1,claro,1 +71615,bitel,Bitel-Internet,nil,1,nil,1 +71617,entel.pe,EntelPE,nil,1,nil,0 +71617,location.entel.pe,EntelLocation,nil,1,nil,0 +72201,internet.movil,Quam_WEB,internet,1,internet,1 +72207,wap.gprs.unifon.com.ar,MovistarWAP,wap,1,wap,1 +72207,internet.gprs.unifon.com.ar,Argentina,internet,1,internet,1 +72231,igprs.claro.com.ar,ClaroAR,nil,1,nil,nil +722310,igprs.claro.com.ar,ClaroAR,nil,1,nil,nil +72234,datos.personal.com,PersonalDatos,datos,1,datos,1 +72234,internet.personal.com,Argentina,internet,1,internet,0 +72236,gprs.nuestro.com.ar,Argentina,nil,1,gprs,0 +722340,datos.personal.com,Argentina,adgj,1,gprs,0 +722340,internet.personal.com,Argentina,internet,1,internet,0 +722341,datos.personal.com,PersonalDatos,datos,1,datos,1 +722341,internet.personal.com,Argentina,internet,1,internet,0 +72402,timbrasil.br,TIMConnect,tim,1,tim,1 +72403,timbrasil.br,TIMConnect,tim,1,tim,1 +72404,timbrasil.br,TIMConnect,tim,1,tim,1 +72405,java.claro.com.br,JavaSession,claro,1,claro,nil +72406,zap.vivo.com.br,VivoInternet,vivo,1,vivo,1 +72407,sercomtel.com.br,SCTLGPRS,sercomtel,1,sercomtel,nil +72410,zap.vivo.com.br,VivoInternet,vivo,1,vivo,1 +72411,zap.vivo.com.br,VivoInternet,vivo,1,vivo,1 +72415,sercomtel.com.br,Sercomtel,sercomtel,1,sercomtel,1 +72416,gprs.oi.com.br,OiGPRSInternet,nil,1,nil,nil +72417,internet.br,Surf,nil,1,nil,1 +72419,gprs.telemigcelular.com.br,TelemigCGPRS,celular,1,celular,nil +72423,zap.vivo.com.br,VivoInternet,vivo,1,vivo,1 +72424,gprs.oi.com.br,OI,oi,1,oi,1 +72431,gprs.oi.com.br,OiGPRSInternet,nil,1,nil,nil +72432,ctbc.br,CTBC,1212,1,CTBC,1 +72433,ctbc.br,CTBC,1212,1,CTBC,1 +72434,ctbc.br,CTBC,1212,1,CTBC,1 +72439,wap.nextel3g.net.br,NextelWAP,nil,1,nil,0 +72454,portoconecta.br,PortoSeguroConecta,nil,1,nil,0 +73001,bam.entelpcs.cl,InternetMovil,entelpcs,1,entelpcs,1 +73009,wap.nextelmovil.cl,InternetNextel,nil,1,nil,0 +73010,bam.entelpcs.cl,InternetMovil,entelpcs,1,entelpcs,1 +73002,wap.tmovil.cl,MovistarAPLICACIONES,wap,1,wap,1 +73003,bam.clarochile.cl,BandaAnchaMovil,clarochile,1,clarochile,1 +73007,web.gtdmovil.cl,web,webgtd,1,webgtd,1 +73008,movil.vtr.com,Internet,vtrmovil,1,vtrmovil,2 +73008,wap.vtr.com,Wap,nil,1,nil,0 +73212,internet.movistar.com.co,MovistarINTERNET,movistar,1,movistar,1 +732101,internet.comcel.com.co,COMCEL,COMCELWEB,1,COMCELWEB,1 +732103,web.colombiamovil.com.co,TIGOWEB,nil,1,nil,1 +732103,moviletb.net.co,InternetETB,etb,1,etb,0 +732103,movilexito.net.co,InternetÉxito,nil,1,nil,1 +732103,www.une.net.co,UNE,une,1,une,0 +732111,web.colombiamovil.com.co,TIGOWEB,nil,1,nil,1 +732111,moviletb.net.co,InternetETB,etb,1,etb,0 +732111,movilexito.net.co,InternetÉxito,nil,1,nil,1 +732111,www.une.net.co,UNE,une,1,une,0 +732123,internet.movistar.com.co,MovistarINTERNET,movistar,1,movistar,1 +732123,web.vmc.net.co,VirginMobile,nil,1,nil,1 +732130,lte.avantel.com.co,Avantel,nil,1,nil,0 +732187,internetmovil.etb.net.co,ETB4G,nil,1,nil,0 +73401,internet.digitel.ve,Digitel412,nil,1,nil,nil +73401,gprsweb.digitel.ve,Venezuela,nil,1,nil,1 +73402,internet.digitel.ve,Digitel412,nil,1,nil,nil +73402,gprsweb.digitel.ve,Venezuela,nil,1,nil,1 +73403,internet.digitel.ve,Digitel412,nil,1,nil,nil +73403,gprsweb.digitel.ve,Venezuela,nil,1,nil,1 +73404,internet.movistar.ve,MovistarINTERNET,nil,1,nil,nil +73404,wap.movistar.ve,MovistarWAP,nil,1,nil,nil +73406,int.movilnet.com.ve,MODEM,nil,1,nil,nil +73601,internet.nuevatel.com,VIVA3G,nil,1,nil,1 +73602,wap.movil.com.bo,ENTELWAPGPRS,nil,1,nil,1 +73603,wap.tigo.bo,WAPTIGO,nil,1,nil,1 +73801,default,Digicel,nil,1,nil,nil +73801,wap.digicelgy.com,Guyana,wap,1,wap,1 +73802,default,GT&TCellinkPlus,nil,1,nil,nil +74000,internet.movistar.com.ec,MovistarINTERNET,movistar,1,movistar,1 +74001,internet.claro.com.ec,InternetClaro,nil,1,nil,nil +740010,internet.claro.com.ec,InternetClaro,nil,1,nil,nil +74002,internet3gsp.alegro.net.ec,CNT3G,nil,1,nil,nil +74401,vox.internet,VOXINTERNET,nil,1,nil,1 +74401,vox.wap,Paraguay,nil,1,nil,1 +74402,igprs.claro.com.py,ClaroPY,ctigprs999,1,ctigprs,1 +74404,internet.tigo.py,TIGOPY,nil,1,nil,1 +74405,internet,PersonalDatosPy,personal,1,personal,1 +74602,default,Telesur,nil,1,nil,nil +74603,web.digicelsr.com,Suriname,nil,1,nil,1 +74603,wap.digicelsr.com,Suriname,wap,1,wap,1 +74801,wap,wapANCEL,nil,1,nil,1 +74801,gprs.ancel,gprsANCEL,nil,1,nil,1 +74807,webapn.movistar.com.uy,MovistarINTERNET,movistar,1,movistar,1 +74810,igprs.claro.com.uy,ClaroUY,ctigprs999,1,ctigprs,1 +28310,Internet,OrangeArmeniaInternet,nil,1,nil,1 +65202,internet.orange.co.bw,OrangeWAPBW,nil,1,nil,nil +62402,orangecmgprs,OrangeCM,orange,1,orange,nil +64602,orangeworld,OrangeWorldMG,orange,1,world,nil +90128,ciot.vodafone.com,CIOTVodafone,vodafone,1,vodafone,nil +90137,mobiledata,mobiledata,nil,1,nil,nil +90143,em,EMnify,nil,1,nil,nil +90158,bicsapn,BICSInternet,nil,1,nil,nil +25050,internet.sberbank-tele.com,Sberbank-TelecomInternet,nil,1,nil,nil +20630,web.be,Unleashed,nil,1,nil,nil +22207,web.kenamobile.it,KenaMobileWeb,nil,1,nil,nil +50519,data.lycamobile.com.au,Lycamobile,nil,1,nil,1 +24223,data.lyca-mobile.no,Lycamobile,nil,1,nil,1 +22854,data.lycamobile.ch,Lycamobile,nil,1,nil,1 +23208,data.lycamobile.at,Lycamobile,nil,1,nil,1 +20606,data.lycamobile.be,Lycamobile,nil,1,nil,1 +26243,data.lycamobile.de,Lycamobile,nil,1,nil,1 +23812,data.lycamobile.dk,Lycamobile,nil,1,nil,1 +21425,data.lycamobile.es,Lycamobile,nil,1,nil,1 +20825,data.lycamobile.fr,Lycamobile,nil,1,nil,1 +27213,data.lycamobile.ie,Lycamobile,nil,1,nil,1 +20409,data.lycamobile.nl,Lycamobile,nil,1,nil,1 +26009,data.lycamobile.pl,Lycamobile,nil,1,nil,1 +26804,data.lycamobile.pt,Lycamobile,nil,1,nil,1 +22616,data.lycamobile.ro,Lycamobile,nil,1,nil,1 +24012,data.lycamobile.se,Lycamobile,nil,1,nil,1 +22235,data.lycamobile.it,Lycamobile,nil,1,nil,1 +311960,data.lycamobile.com,Lycamobile,nil,1,nil,1 +64126,data.lycamobile.ug,Lycamobile,nil,1,nil,1 +29404,data.lycamobile.mk,Lycamobile,nil,1,nil,1 +65553,data.lycamobile.co.za,Lycamobile,nil,1,nil,1 +23457,mobile.sky,Internet,nil,1,nil,0 +29701,flat,Internet,nil,1,nil,3 +29701,internet,Internet,nil,1,nil,3 +29702,tmcg-4g,TelekomInternet,38267,1,38267,1 +29703,mtelinternet,mTelInternet,068,1,internet,2 +40421,jionet,Jio,nil,1,nil,3 +404854,jionet,Jio,nil,1,nil,3 +404855,jionet,Jio,nil,1,nil,3 +404856,jionet,Jio,nil,1,nil,3 +404857,jionet,Jio,nil,1,nil,3 +404858,jionet,Jio,nil,1,nil,3 +404859,jionet,Jio,nil,1,nil,3 +404860,jionet,Jio,nil,1,nil,3 +404861,jionet,Jio,nil,1,nil,3 +404862,jionet,Jio,nil,1,nil,3 +404863,jionet,Jio,nil,1,nil,3 +404864,jionet,Jio,nil,1,nil,3 +404865,jionet,Jio,nil,1,nil,3 +404866,jionet,Jio,nil,1,nil,3 +404867,jionet,Jio,nil,1,nil,3 +404868,jionet,Jio,nil,1,nil,3 +404869,jionet,Jio,nil,1,nil,3 +404870,jionet,Jio,nil,1,nil,3 +404871,jionet,Jio,nil,1,nil,3 +404872,jionet,Jio,nil,1,nil,3 +404873,jionet,Jio,nil,1,nil,3 +404874,jionet,Jio,nil,1,nil,3 +22801,shared.m2m.ch,SwisscomM2M,nil,1,nil,0 +27202,Open.internet,3Ireland,nil,1,nil,nil +24008,services.telenor.se,TelenorMobilsurf,nil,1,nil,nil +310410,accessrgn.net,AT&T,nil,1,nil,nil +24603,static.tele2.lt,Tele2,nil,1,nil,nil +24602,bangapro,Bite,nil,1,nil,nil +24601,gprs.fix-ip.omnitel1.net,Telia,nil,1,nil,nil +20404,truphone.com,Truphone,nil,1,nil,nil +20433,truphone.com,Truphone,nil,1,nil,nil +20809,truphone.com,Truphone,nil,1,nil,nil +20812,truphone.com,Truphone,nil,1,nil,nil +21427,truphone.com,Truphone,nil,1,nil,nil +23425,truphone.com,Truphone,nil,1,nil,nil +26033,truphone.com,Truphone,nil,1,nil,nil +26242,truphone.com,Truphone,nil,1,nil,nil +31030,truphone.com,Truphone,nil,1,nil,nil +310300,truphone.com,Truphone,nil,1,nil,nil +45408,truphone.com,Truphone,nil,1,nil,nil +50538,truphone.com,Truphone,nil,1,nil,nil +50502,truphone.com,Truphone,nil,1,nil,nil +20828,datapro,AIF,nil,1,nil,nil +90140,iot.1nce.net,1NCE,nil,1,nil,nil +00101,internet,Amarisoft,nil,1,nil,nil +00101,default,Amarisoft,nil,1,nil,nil +40001,internet,Azercell,nil,1,nil,nil +310004,VZWINTERNET,Verizon,nil,3,nil,nil +310010,VZWINTERNET,Verizon,nil,3,nil,nil +310012,VZWINTERNET,Verizon,nil,3,nil,nil +310013,VZWINTERNET,Verizon,nil,3,nil,nil +310350,VZWINTERNET,Verizon,nil,3,nil,nil +310590,VZWINTERNET,Verizon,nil,3,nil,nil +310591,VZWINTERNET,Verizon,nil,3,nil,nil +310592,VZWINTERNET,Verizon,nil,3,nil,nil +310593,VZWINTERNET,Verizon,nil,3,nil,nil +310594,VZWINTERNET,Verizon,nil,3,nil,nil +310595,VZWINTERNET,Verizon,nil,3,nil,nil +310596,VZWINTERNET,Verizon,nil,3,nil,nil +310597,VZWINTERNET,Verizon,nil,3,nil,nil +310598,VZWINTERNET,Verizon,nil,3,nil,nil +310599,VZWINTERNET,Verizon,nil,3,nil,nil +310820,VZWINTERNET,Verizon,nil,3,nil,nil +310890,VZWINTERNET,Verizon,nil,3,nil,nil +310891,VZWINTERNET,Verizon,nil,3,nil,nil +310892,VZWINTERNET,Verizon,nil,3,nil,nil +310893,VZWINTERNET,Verizon,nil,3,nil,nil +310894,VZWINTERNET,Verizon,nil,3,nil,nil +310895,VZWINTERNET,Verizon,nil,3,nil,nil +310896,VZWINTERNET,Verizon,nil,3,nil,nil +310897,VZWINTERNET,Verizon,nil,3,nil,nil +310898,VZWINTERNET,Verizon,nil,3,nil,nil +310899,VZWINTERNET,Verizon,nil,3,nil,nil +310910,VZWINTERNET,Verizon,nil,3,nil,nil +311110,VZWINTERNET,Verizon,nil,3,nil,nil +311270,VZWINTERNET,Verizon,nil,3,nil,nil +311271,VZWINTERNET,Verizon,nil,3,nil,nil +311272,VZWINTERNET,Verizon,nil,3,nil,nil +311273,VZWINTERNET,Verizon,nil,3,nil,nil +311274,VZWINTERNET,Verizon,nil,3,nil,nil +311275,VZWINTERNET,Verizon,nil,3,nil,nil +311276,VZWINTERNET,Verizon,nil,3,nil,nil +311277,VZWINTERNET,Verizon,nil,3,nil,nil +311278,VZWINTERNET,Verizon,nil,3,nil,nil +311279,VZWINTERNET,Verizon,nil,3,nil,nil +311280,VZWINTERNET,Verizon,nil,3,nil,nil +311281,VZWINTERNET,Verizon,nil,3,nil,nil +311282,VZWINTERNET,Verizon,nil,3,nil,nil +311283,VZWINTERNET,Verizon,nil,3,nil,nil +311284,VZWINTERNET,Verizon,nil,3,nil,nil +311285,VZWINTERNET,Verizon,nil,3,nil,nil +311286,VZWINTERNET,Verizon,nil,3,nil,nil +311287,VZWINTERNET,Verizon,nil,3,nil,nil +311288,VZWINTERNET,Verizon,nil,3,nil,nil +311289,VZWINTERNET,Verizon,nil,3,nil,nil +311390,VZWINTERNET,Verizon,nil,3,nil,nil +311480,VZWINTERNET,Verizon,nil,3,nil,nil +311481,VZWINTERNET,Verizon,nil,3,nil,nil +311482,VZWINTERNET,Verizon,nil,3,nil,nil +311483,VZWINTERNET,Verizon,nil,3,nil,nil +311484,VZWINTERNET,Verizon,nil,3,nil,nil +311485,VZWINTERNET,Verizon,nil,3,nil,nil +311486,VZWINTERNET,Verizon,nil,3,nil,nil +311487,VZWINTERNET,Verizon,nil,3,nil,nil +311488,VZWINTERNET,Verizon,nil,3,nil,nil +311489,VZWINTERNET,Verizon,nil,3,nil,nil +311590,VZWINTERNET,Verizon,nil,3,nil,nil +312040,VZWINTERNET,Verizon,nil,3,nil,nil +312160,VZWINTERNET,Verizon,nil,3,nil,nil +312770,VZWINTERNET,Verizon,nil,3,nil,nil +310010,VZWINTERNET,Verizon,nil,3,nil,nil +310012,VZWINTERNET,Verizon,nil,3,nil,nil +310004,ne01.vzwstatic,Verizon,nil,3,nil,nil +310010,ne01.vzwstatic,Verizon,nil,3,nil,nil +310012,ne01.vzwstatic,Verizon,nil,3,nil,nil +310013,ne01.vzwstatic,Verizon,nil,3,nil,nil +310350,ne01.vzwstatic,Verizon,nil,3,nil,nil +310590,ne01.vzwstatic,Verizon,nil,3,nil,nil +310591,ne01.vzwstatic,Verizon,nil,3,nil,nil +310592,ne01.vzwstatic,Verizon,nil,3,nil,nil +310593,ne01.vzwstatic,Verizon,nil,3,nil,nil +310594,ne01.vzwstatic,Verizon,nil,3,nil,nil +310595,ne01.vzwstatic,Verizon,nil,3,nil,nil +310596,ne01.vzwstatic,Verizon,nil,3,nil,nil +310597,ne01.vzwstatic,Verizon,nil,3,nil,nil +310598,ne01.vzwstatic,Verizon,nil,3,nil,nil +310599,ne01.vzwstatic,Verizon,nil,3,nil,nil +310820,ne01.vzwstatic,Verizon,nil,3,nil,nil +310890,ne01.vzwstatic,Verizon,nil,3,nil,nil +310891,ne01.vzwstatic,Verizon,nil,3,nil,nil +310892,ne01.vzwstatic,Verizon,nil,3,nil,nil +310893,ne01.vzwstatic,Verizon,nil,3,nil,nil +310894,ne01.vzwstatic,Verizon,nil,3,nil,nil +310895,ne01.vzwstatic,Verizon,nil,3,nil,nil +310896,ne01.vzwstatic,Verizon,nil,3,nil,nil +310897,ne01.vzwstatic,Verizon,nil,3,nil,nil +310898,ne01.vzwstatic,Verizon,nil,3,nil,nil +310899,ne01.vzwstatic,Verizon,nil,3,nil,nil +310910,ne01.vzwstatic,Verizon,nil,3,nil,nil +311110,ne01.vzwstatic,Verizon,nil,3,nil,nil +311270,ne01.vzwstatic,Verizon,nil,3,nil,nil +311271,ne01.vzwstatic,Verizon,nil,3,nil,nil +311272,ne01.vzwstatic,Verizon,nil,3,nil,nil +311273,ne01.vzwstatic,Verizon,nil,3,nil,nil +311274,ne01.vzwstatic,Verizon,nil,3,nil,nil +311275,ne01.vzwstatic,Verizon,nil,3,nil,nil +311276,ne01.vzwstatic,Verizon,nil,3,nil,nil +311277,ne01.vzwstatic,Verizon,nil,3,nil,nil +311278,ne01.vzwstatic,Verizon,nil,3,nil,nil +311279,ne01.vzwstatic,Verizon,nil,3,nil,nil +311280,ne01.vzwstatic,Verizon,nil,3,nil,nil +311281,ne01.vzwstatic,Verizon,nil,3,nil,nil +311282,ne01.vzwstatic,Verizon,nil,3,nil,nil +311283,ne01.vzwstatic,Verizon,nil,3,nil,nil +311284,ne01.vzwstatic,Verizon,nil,3,nil,nil +311285,ne01.vzwstatic,Verizon,nil,3,nil,nil +311286,ne01.vzwstatic,Verizon,nil,3,nil,nil +311287,ne01.vzwstatic,Verizon,nil,3,nil,nil +311288,ne01.vzwstatic,Verizon,nil,3,nil,nil +311289,ne01.vzwstatic,Verizon,nil,3,nil,nil +311390,ne01.vzwstatic,Verizon,nil,3,nil,nil +311480,ne01.vzwstatic,Verizon,nil,3,nil,nil +311481,ne01.vzwstatic,Verizon,nil,3,nil,nil +311482,ne01.vzwstatic,Verizon,nil,3,nil,nil +311483,ne01.vzwstatic,Verizon,nil,3,nil,nil +311484,ne01.vzwstatic,Verizon,nil,3,nil,nil +311485,ne01.vzwstatic,Verizon,nil,3,nil,nil +311486,ne01.vzwstatic,Verizon,nil,3,nil,nil +311487,ne01.vzwstatic,Verizon,nil,3,nil,nil +311488,ne01.vzwstatic,Verizon,nil,3,nil,nil +311489,ne01.vzwstatic,Verizon,nil,3,nil,nil +311590,ne01.vzwstatic,Verizon,nil,3,nil,nil +312040,ne01.vzwstatic,Verizon,nil,3,nil,nil +312160,ne01.vzwstatic,Verizon,nil,3,nil,nil +312770,ne01.vzwstatic,Verizon,nil,3,nil,nil +310004,nw01.vzwstatic,Verizon,nil,3,nil,nil +310010,nw01.vzwstatic,Verizon,nil,3,nil,nil +310012,nw01.vzwstatic,Verizon,nil,3,nil,nil +310013,nw01.vzwstatic,Verizon,nil,3,nil,nil +310350,nw01.vzwstatic,Verizon,nil,3,nil,nil +310590,nw01.vzwstatic,Verizon,nil,3,nil,nil +310591,nw01.vzwstatic,Verizon,nil,3,nil,nil +310592,nw01.vzwstatic,Verizon,nil,3,nil,nil +310593,nw01.vzwstatic,Verizon,nil,3,nil,nil +310594,nw01.vzwstatic,Verizon,nil,3,nil,nil +310595,nw01.vzwstatic,Verizon,nil,3,nil,nil +310596,nw01.vzwstatic,Verizon,nil,3,nil,nil +310597,nw01.vzwstatic,Verizon,nil,3,nil,nil +310598,nw01.vzwstatic,Verizon,nil,3,nil,nil +310599,nw01.vzwstatic,Verizon,nil,3,nil,nil +310820,nw01.vzwstatic,Verizon,nil,3,nil,nil +310890,nw01.vzwstatic,Verizon,nil,3,nil,nil +310891,nw01.vzwstatic,Verizon,nil,3,nil,nil +310892,nw01.vzwstatic,Verizon,nil,3,nil,nil +310893,nw01.vzwstatic,Verizon,nil,3,nil,nil +310894,nw01.vzwstatic,Verizon,nil,3,nil,nil +310895,nw01.vzwstatic,Verizon,nil,3,nil,nil +310896,nw01.vzwstatic,Verizon,nil,3,nil,nil +310897,nw01.vzwstatic,Verizon,nil,3,nil,nil +310898,nw01.vzwstatic,Verizon,nil,3,nil,nil +310899,nw01.vzwstatic,Verizon,nil,3,nil,nil +310910,nw01.vzwstatic,Verizon,nil,3,nil,nil +311110,nw01.vzwstatic,Verizon,nil,3,nil,nil +311270,nw01.vzwstatic,Verizon,nil,3,nil,nil +311271,nw01.vzwstatic,Verizon,nil,3,nil,nil +311272,nw01.vzwstatic,Verizon,nil,3,nil,nil +311273,nw01.vzwstatic,Verizon,nil,3,nil,nil +311274,nw01.vzwstatic,Verizon,nil,3,nil,nil +311275,nw01.vzwstatic,Verizon,nil,3,nil,nil +311276,nw01.vzwstatic,Verizon,nil,3,nil,nil +311277,nw01.vzwstatic,Verizon,nil,3,nil,nil +311278,nw01.vzwstatic,Verizon,nil,3,nil,nil +311279,nw01.vzwstatic,Verizon,nil,3,nil,nil +311280,nw01.vzwstatic,Verizon,nil,3,nil,nil +311281,nw01.vzwstatic,Verizon,nil,3,nil,nil +311282,nw01.vzwstatic,Verizon,nil,3,nil,nil +311283,nw01.vzwstatic,Verizon,nil,3,nil,nil +311284,nw01.vzwstatic,Verizon,nil,3,nil,nil +311285,nw01.vzwstatic,Verizon,nil,3,nil,nil +311286,nw01.vzwstatic,Verizon,nil,3,nil,nil +311287,nw01.vzwstatic,Verizon,nil,3,nil,nil +311288,nw01.vzwstatic,Verizon,nil,3,nil,nil +311289,nw01.vzwstatic,Verizon,nil,3,nil,nil +311390,nw01.vzwstatic,Verizon,nil,3,nil,nil +311480,nw01.vzwstatic,Verizon,nil,3,nil,nil +311481,nw01.vzwstatic,Verizon,nil,3,nil,nil +311482,nw01.vzwstatic,Verizon,nil,3,nil,nil +311483,nw01.vzwstatic,Verizon,nil,3,nil,nil +311484,nw01.vzwstatic,Verizon,nil,3,nil,nil +311485,nw01.vzwstatic,Verizon,nil,3,nil,nil +311486,nw01.vzwstatic,Verizon,nil,3,nil,nil +311487,nw01.vzwstatic,Verizon,nil,3,nil,nil +311488,nw01.vzwstatic,Verizon,nil,3,nil,nil +311489,nw01.vzwstatic,Verizon,nil,3,nil,nil +311590,nw01.vzwstatic,Verizon,nil,3,nil,nil +312040,nw01.vzwstatic,Verizon,nil,3,nil,nil +312160,nw01.vzwstatic,Verizon,nil,3,nil,nil +312770,nw01.vzwstatic,Verizon,nil,3,nil,nil +310004,so01.vzwstatic,Verizon,nil,3,nil,nil +310010,so01.vzwstatic,Verizon,nil,3,nil,nil +310012,so01.vzwstatic,Verizon,nil,3,nil,nil +310013,so01.vzwstatic,Verizon,nil,3,nil,nil +310350,so01.vzwstatic,Verizon,nil,3,nil,nil +310590,so01.vzwstatic,Verizon,nil,3,nil,nil +310591,so01.vzwstatic,Verizon,nil,3,nil,nil +310592,so01.vzwstatic,Verizon,nil,3,nil,nil +310593,so01.vzwstatic,Verizon,nil,3,nil,nil +310594,so01.vzwstatic,Verizon,nil,3,nil,nil +310595,so01.vzwstatic,Verizon,nil,3,nil,nil +310596,so01.vzwstatic,Verizon,nil,3,nil,nil +310597,so01.vzwstatic,Verizon,nil,3,nil,nil +310598,so01.vzwstatic,Verizon,nil,3,nil,nil +310599,so01.vzwstatic,Verizon,nil,3,nil,nil +310820,so01.vzwstatic,Verizon,nil,3,nil,nil +310890,so01.vzwstatic,Verizon,nil,3,nil,nil +310891,so01.vzwstatic,Verizon,nil,3,nil,nil +310892,so01.vzwstatic,Verizon,nil,3,nil,nil +310893,so01.vzwstatic,Verizon,nil,3,nil,nil +310894,so01.vzwstatic,Verizon,nil,3,nil,nil +310895,so01.vzwstatic,Verizon,nil,3,nil,nil +310896,so01.vzwstatic,Verizon,nil,3,nil,nil +310897,so01.vzwstatic,Verizon,nil,3,nil,nil +310898,so01.vzwstatic,Verizon,nil,3,nil,nil +310899,so01.vzwstatic,Verizon,nil,3,nil,nil +310910,so01.vzwstatic,Verizon,nil,3,nil,nil +311110,so01.vzwstatic,Verizon,nil,3,nil,nil +311270,so01.vzwstatic,Verizon,nil,3,nil,nil +311271,so01.vzwstatic,Verizon,nil,3,nil,nil +311272,so01.vzwstatic,Verizon,nil,3,nil,nil +311273,so01.vzwstatic,Verizon,nil,3,nil,nil +311274,so01.vzwstatic,Verizon,nil,3,nil,nil +311275,so01.vzwstatic,Verizon,nil,3,nil,nil +311276,so01.vzwstatic,Verizon,nil,3,nil,nil +311277,so01.vzwstatic,Verizon,nil,3,nil,nil +311278,so01.vzwstatic,Verizon,nil,3,nil,nil +311279,so01.vzwstatic,Verizon,nil,3,nil,nil +311280,so01.vzwstatic,Verizon,nil,3,nil,nil +311281,so01.vzwstatic,Verizon,nil,3,nil,nil +311282,so01.vzwstatic,Verizon,nil,3,nil,nil +311283,so01.vzwstatic,Verizon,nil,3,nil,nil +311284,so01.vzwstatic,Verizon,nil,3,nil,nil +311285,so01.vzwstatic,Verizon,nil,3,nil,nil +311286,so01.vzwstatic,Verizon,nil,3,nil,nil +311287,so01.vzwstatic,Verizon,nil,3,nil,nil +311288,so01.vzwstatic,Verizon,nil,3,nil,nil +311289,so01.vzwstatic,Verizon,nil,3,nil,nil +311390,so01.vzwstatic,Verizon,nil,3,nil,nil +311480,so01.vzwstatic,Verizon,nil,3,nil,nil +311481,so01.vzwstatic,Verizon,nil,3,nil,nil +311482,so01.vzwstatic,Verizon,nil,3,nil,nil +311483,so01.vzwstatic,Verizon,nil,3,nil,nil +311484,so01.vzwstatic,Verizon,nil,3,nil,nil +311485,so01.vzwstatic,Verizon,nil,3,nil,nil +311486,so01.vzwstatic,Verizon,nil,3,nil,nil +311487,so01.vzwstatic,Verizon,nil,3,nil,nil +311488,so01.vzwstatic,Verizon,nil,3,nil,nil +311489,so01.vzwstatic,Verizon,nil,3,nil,nil +311590,so01.vzwstatic,Verizon,nil,3,nil,nil +312040,so01.vzwstatic,Verizon,nil,3,nil,nil +312160,so01.vzwstatic,Verizon,nil,3,nil,nil +312770,so01.vzwstatic,Verizon,nil,3,nil,nil +310004,mw01.vzwstatic,Verizon,nil,3,nil,nil +310010,mw01.vzwstatic,Verizon,nil,3,nil,nil +310012,mw01.vzwstatic,Verizon,nil,3,nil,nil +310013,mw01.vzwstatic,Verizon,nil,3,nil,nil +310350,mw01.vzwstatic,Verizon,nil,3,nil,nil +310590,mw01.vzwstatic,Verizon,nil,3,nil,nil +310591,mw01.vzwstatic,Verizon,nil,3,nil,nil +310592,mw01.vzwstatic,Verizon,nil,3,nil,nil +310593,mw01.vzwstatic,Verizon,nil,3,nil,nil +310594,mw01.vzwstatic,Verizon,nil,3,nil,nil +310595,mw01.vzwstatic,Verizon,nil,3,nil,nil +310596,mw01.vzwstatic,Verizon,nil,3,nil,nil +310597,mw01.vzwstatic,Verizon,nil,3,nil,nil +310598,mw01.vzwstatic,Verizon,nil,3,nil,nil +310599,mw01.vzwstatic,Verizon,nil,3,nil,nil +310820,mw01.vzwstatic,Verizon,nil,3,nil,nil +310890,mw01.vzwstatic,Verizon,nil,3,nil,nil +310891,mw01.vzwstatic,Verizon,nil,3,nil,nil +310892,mw01.vzwstatic,Verizon,nil,3,nil,nil +310893,mw01.vzwstatic,Verizon,nil,3,nil,nil +310894,mw01.vzwstatic,Verizon,nil,3,nil,nil +310895,mw01.vzwstatic,Verizon,nil,3,nil,nil +310896,mw01.vzwstatic,Verizon,nil,3,nil,nil +310897,mw01.vzwstatic,Verizon,nil,3,nil,nil +310898,mw01.vzwstatic,Verizon,nil,3,nil,nil +310899,mw01.vzwstatic,Verizon,nil,3,nil,nil +310910,mw01.vzwstatic,Verizon,nil,3,nil,nil +311110,mw01.vzwstatic,Verizon,nil,3,nil,nil +311270,mw01.vzwstatic,Verizon,nil,3,nil,nil +311271,mw01.vzwstatic,Verizon,nil,3,nil,nil +311272,mw01.vzwstatic,Verizon,nil,3,nil,nil +311273,mw01.vzwstatic,Verizon,nil,3,nil,nil +311274,mw01.vzwstatic,Verizon,nil,3,nil,nil +311275,mw01.vzwstatic,Verizon,nil,3,nil,nil +311276,mw01.vzwstatic,Verizon,nil,3,nil,nil +311277,mw01.vzwstatic,Verizon,nil,3,nil,nil +311278,mw01.vzwstatic,Verizon,nil,3,nil,nil +311279,mw01.vzwstatic,Verizon,nil,3,nil,nil +311280,mw01.vzwstatic,Verizon,nil,3,nil,nil +311281,mw01.vzwstatic,Verizon,nil,3,nil,nil +311282,mw01.vzwstatic,Verizon,nil,3,nil,nil +311283,mw01.vzwstatic,Verizon,nil,3,nil,nil +311284,mw01.vzwstatic,Verizon,nil,3,nil,nil +311285,mw01.vzwstatic,Verizon,nil,3,nil,nil +311286,mw01.vzwstatic,Verizon,nil,3,nil,nil +311287,mw01.vzwstatic,Verizon,nil,3,nil,nil +311288,mw01.vzwstatic,Verizon,nil,3,nil,nil +311289,mw01.vzwstatic,Verizon,nil,3,nil,nil +311390,mw01.vzwstatic,Verizon,nil,3,nil,nil +311480,mw01.vzwstatic,Verizon,nil,3,nil,nil +311481,mw01.vzwstatic,Verizon,nil,3,nil,nil +311482,mw01.vzwstatic,Verizon,nil,3,nil,nil +311483,mw01.vzwstatic,Verizon,nil,3,nil,nil +311484,mw01.vzwstatic,Verizon,nil,3,nil,nil +311485,mw01.vzwstatic,Verizon,nil,3,nil,nil +311486,mw01.vzwstatic,Verizon,nil,3,nil,nil +311487,mw01.vzwstatic,Verizon,nil,3,nil,nil +311488,mw01.vzwstatic,Verizon,nil,3,nil,nil +311489,mw01.vzwstatic,Verizon,nil,3,nil,nil +311590,mw01.vzwstatic,Verizon,nil,3,nil,nil +312040,mw01.vzwstatic,Verizon,nil,3,nil,nil +312160,mw01.vzwstatic,Verizon,nil,3,nil,nil +312770,mw01.vzwstatic,Verizon,nil,3,nil,nil +310004,we01.vzwstatic,Verizon,nil,3,nil,nil +310010,we01.vzwstatic,Verizon,nil,3,nil,nil +310012,we01.vzwstatic,Verizon,nil,3,nil,nil +310013,we01.vzwstatic,Verizon,nil,3,nil,nil +310350,we01.vzwstatic,Verizon,nil,3,nil,nil +310590,we01.vzwstatic,Verizon,nil,3,nil,nil +310591,we01.vzwstatic,Verizon,nil,3,nil,nil +310592,we01.vzwstatic,Verizon,nil,3,nil,nil +310593,we01.vzwstatic,Verizon,nil,3,nil,nil +310594,we01.vzwstatic,Verizon,nil,3,nil,nil +310595,we01.vzwstatic,Verizon,nil,3,nil,nil +310596,we01.vzwstatic,Verizon,nil,3,nil,nil +310597,we01.vzwstatic,Verizon,nil,3,nil,nil +310598,we01.vzwstatic,Verizon,nil,3,nil,nil +310599,we01.vzwstatic,Verizon,nil,3,nil,nil +310820,we01.vzwstatic,Verizon,nil,3,nil,nil +310890,we01.vzwstatic,Verizon,nil,3,nil,nil +310891,we01.vzwstatic,Verizon,nil,3,nil,nil +310892,we01.vzwstatic,Verizon,nil,3,nil,nil +310893,we01.vzwstatic,Verizon,nil,3,nil,nil +310894,we01.vzwstatic,Verizon,nil,3,nil,nil +310895,we01.vzwstatic,Verizon,nil,3,nil,nil +310896,we01.vzwstatic,Verizon,nil,3,nil,nil +310897,we01.vzwstatic,Verizon,nil,3,nil,nil +310898,we01.vzwstatic,Verizon,nil,3,nil,nil +310899,we01.vzwstatic,Verizon,nil,3,nil,nil +310910,we01.vzwstatic,Verizon,nil,3,nil,nil +311110,we01.vzwstatic,Verizon,nil,3,nil,nil +311270,we01.vzwstatic,Verizon,nil,3,nil,nil +311271,we01.vzwstatic,Verizon,nil,3,nil,nil +311272,we01.vzwstatic,Verizon,nil,3,nil,nil +311273,we01.vzwstatic,Verizon,nil,3,nil,nil +311274,we01.vzwstatic,Verizon,nil,3,nil,nil +311275,we01.vzwstatic,Verizon,nil,3,nil,nil +311276,we01.vzwstatic,Verizon,nil,3,nil,nil +311277,we01.vzwstatic,Verizon,nil,3,nil,nil +311278,we01.vzwstatic,Verizon,nil,3,nil,nil +311279,we01.vzwstatic,Verizon,nil,3,nil,nil +311280,we01.vzwstatic,Verizon,nil,3,nil,nil +311281,we01.vzwstatic,Verizon,nil,3,nil,nil +311282,we01.vzwstatic,Verizon,nil,3,nil,nil +311283,we01.vzwstatic,Verizon,nil,3,nil,nil +311284,we01.vzwstatic,Verizon,nil,3,nil,nil +311285,we01.vzwstatic,Verizon,nil,3,nil,nil +311286,we01.vzwstatic,Verizon,nil,3,nil,nil +311287,we01.vzwstatic,Verizon,nil,3,nil,nil +311288,we01.vzwstatic,Verizon,nil,3,nil,nil +311289,we01.vzwstatic,Verizon,nil,3,nil,nil +311390,we01.vzwstatic,Verizon,nil,3,nil,nil +311480,we01.vzwstatic,Verizon,nil,3,nil,nil +311481,we01.vzwstatic,Verizon,nil,3,nil,nil +311482,we01.vzwstatic,Verizon,nil,3,nil,nil +311483,we01.vzwstatic,Verizon,nil,3,nil,nil +311484,we01.vzwstatic,Verizon,nil,3,nil,nil +311485,we01.vzwstatic,Verizon,nil,3,nil,nil +311486,we01.vzwstatic,Verizon,nil,3,nil,nil +311487,we01.vzwstatic,Verizon,nil,3,nil,nil +311488,we01.vzwstatic,Verizon,nil,3,nil,nil +311489,we01.vzwstatic,Verizon,nil,3,nil,nil +311590,we01.vzwstatic,Verizon,nil,3,nil,nil +312040,we01.vzwstatic,Verizon,nil,3,nil,nil +312160,we01.vzwstatic,Verizon,nil,3,nil,nil +312770,we01.vzwstatic,Verizon,nil,3,nil,nil +302490,internet.freedommobile.ca,FreedomMobile,nil,1,nil,nil \ No newline at end of file diff --git a/rooter/0optionalapps/ext-blacklist/Makefile b/rooter/0optionalapps/ext-blacklist/Makefile new file mode 100644 index 0000000..0c156e8 --- /dev/null +++ b/rooter/0optionalapps/ext-blacklist/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-blacklist +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-blacklist + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + TITLE:=Install Mac Blacklisting + PKGARCH:=all +endef + +define Package/ext-blacklistdescription + Helper scripts to install Mac Blacklisting +endef + + +define Build/Compile +endef + +define Package/ext-blacklist/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-blacklist)) diff --git a/rooter/0optionalapps/ext-blacklist/files/etc/config/blacklist b/rooter/0optionalapps/ext-blacklist/files/etc/config/blacklist new file mode 100644 index 0000000..00fb552 --- /dev/null +++ b/rooter/0optionalapps/ext-blacklist/files/etc/config/blacklist @@ -0,0 +1,4 @@ + +config blacklist 'blacklist' + + diff --git a/rooter/0optionalapps/ext-blacklist/files/usr/lib/blacklist/blacklist.sh b/rooter/0optionalapps/ext-blacklist/files/usr/lib/blacklist/blacklist.sh new file mode 100644 index 0000000..6775a95 --- /dev/null +++ b/rooter/0optionalapps/ext-blacklist/files/usr/lib/blacklist/blacklist.sh @@ -0,0 +1,32 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Blacklist" "$@" +} + +getmac() { + local config=$1 + config_get src_mac $1 src_mac + if [ ! -z $src_mac ]; then + if [ $create = "0" ]; then + uci set firewall.blacklist=rule + uci set firewall.blacklist.src='lan' + uci set firewall.blacklist.target='REJECT' + uci set firewall.blacklist.dest='wan' + uci set firewall.blacklist.name='Blacklist' + create=1 + fi + uci add_list firewall.blacklist.src_mac=$src_mac + fi +} + +sleep 8 +create="0" +uci -q delete firewall.blacklist +config_load blacklist +config_foreach getmac devices +uci commit firewall +/etc/init.d/firewall restart + +exit 0 diff --git a/rooter/0optionalapps/ext-blacklist/files/usr/lib/blacklist/chkblack.sh b/rooter/0optionalapps/ext-blacklist/files/usr/lib/blacklist/chkblack.sh new file mode 100644 index 0000000..4b13613 --- /dev/null +++ b/rooter/0optionalapps/ext-blacklist/files/usr/lib/blacklist/chkblack.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +log() { + logger -t "Blacklist" "$@" +} + + +result=`ps | grep -i "blacklist.sh" | grep -v "grep" | wc -l` +if [ $result -eq 0 ]; then + /usr/lib/blacklist/blacklist.sh & +fi \ No newline at end of file diff --git a/rooter/0optionalapps/ext-blacklist/files/usr/lib/lua/luci/controller/blacklist.lua b/rooter/0optionalapps/ext-blacklist/files/usr/lib/lua/luci/controller/blacklist.lua new file mode 100644 index 0000000..d132021 --- /dev/null +++ b/rooter/0optionalapps/ext-blacklist/files/usr/lib/lua/luci/controller/blacklist.lua @@ -0,0 +1,13 @@ +module("luci.controller.blacklist", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + local lock = luci.model.uci.cursor():get("custom", "menu", "full") + --if lock == "1" then + page = entry({"admin", "adminmenu", "blacklist"}, cbi("blacklist"), translate("Blacklist by Mac"), 10) + page.dependent = true + --end +end diff --git a/rooter/0optionalapps/ext-blacklist/files/usr/lib/lua/luci/model/cbi/blacklist.lua b/rooter/0optionalapps/ext-blacklist/files/usr/lib/lua/luci/model/cbi/blacklist.lua new file mode 100644 index 0000000..91fa4e7 --- /dev/null +++ b/rooter/0optionalapps/ext-blacklist/files/usr/lib/lua/luci/model/cbi/blacklist.lua @@ -0,0 +1,21 @@ +require("nixio.fs") + +m = Map("blacklist", translate("Blacklist Devices by Mac Address")) + +m.on_after_save = function(self) + luci.sys.call("/usr/lib/blacklist/chkblack.sh &") +end + +s = m:section(TypedSection, "devices", translate("Blacklisted Devices"), translate("Block these devices from using the Internet")) +s.anonymous = true +s.addremove = true + +o = s:option(Value, "src_mac", translate("Device MAC address")) + o.datatype = "list(macaddr)" + o.placeholder = translate("any") + + luci.sys.net.mac_hints(function(mac, name) + o:value(mac, "%s (%s)" %{ mac, name }) + end) + +return m \ No newline at end of file diff --git a/rooter/0optionalapps/ext-blockport/Makefile b/rooter/0optionalapps/ext-blockport/Makefile new file mode 100644 index 0000000..103fa98 --- /dev/null +++ b/rooter/0optionalapps/ext-blockport/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-blockport +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-blockport + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + TITLE:=Install Port Blocking + PKGARCH:=all +endef + +define Package/ext-blockport/description + Helper scripts to install Port Blocking +endef + + +define Build/Compile +endef + +define Package/ext-blockport/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-blockport)) diff --git a/rooter/0optionalapps/ext-blockport/files/etc/config/blockport b/rooter/0optionalapps/ext-blockport/files/etc/config/blockport new file mode 100644 index 0000000..8e69716 --- /dev/null +++ b/rooter/0optionalapps/ext-blockport/files/etc/config/blockport @@ -0,0 +1,4 @@ + +config port 'port' + + diff --git a/rooter/0optionalapps/ext-blockport/files/usr/lib/blockport/blockport.sh b/rooter/0optionalapps/ext-blockport/files/usr/lib/blockport/blockport.sh new file mode 100644 index 0000000..6965bc0 --- /dev/null +++ b/rooter/0optionalapps/ext-blockport/files/usr/lib/blockport/blockport.sh @@ -0,0 +1,37 @@ +#!/bin/sh +. /lib/functions.sh + +config="firewall" + +do_block_remove() { + config_get name $1 name + if [ "$name" = "Block_src" ]; then + uci delete $config".""$1" + fi +} + +handle_port() { + echo $1 + uci add $config rule + uci set $config.@rule[-1].src='lan' + uci set $config.@rule[-1].family='ipv4' + uci set $config.@rule[-1].dest='wan' + uci set $config.@rule[-1].target='DROP' + uci set $config.@rule[-1].proto='tcp' + uci set $config.@rule[-1].src_port="$1" + uci set $config.@rule[-1].name='Block_src' +} + +do_port() { + config_list_foreach "$1" block handle_port +} + +sleep 8 +config_load $config +config_foreach do_block_remove rule + +config_load blockport +config_foreach do_port port +uci commit $config +/etc/init.d/firewall restart 2>/dev/null + diff --git a/rooter/0optionalapps/ext-blockport/files/usr/lib/lua/luci/controller/blockport.lua b/rooter/0optionalapps/ext-blockport/files/usr/lib/lua/luci/controller/blockport.lua new file mode 100644 index 0000000..57bd9ff --- /dev/null +++ b/rooter/0optionalapps/ext-blockport/files/usr/lib/lua/luci/controller/blockport.lua @@ -0,0 +1,15 @@ +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.blockport", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local lock = luci.model.uci.cursor():get("custom", "menu", "full") + --if lock == "1" then + local page + page = entry({"admin", "adminmenu", "blockport"}, cbi("portblk"), _(translate("Port Blocking")), 11) + page.dependent = true + --end +end diff --git a/rooter/0optionalapps/ext-blockport/files/usr/lib/lua/luci/model/cbi/portblk.lua b/rooter/0optionalapps/ext-blockport/files/usr/lib/lua/luci/model/cbi/portblk.lua new file mode 100644 index 0000000..73cd1ea --- /dev/null +++ b/rooter/0optionalapps/ext-blockport/files/usr/lib/lua/luci/model/cbi/portblk.lua @@ -0,0 +1,21 @@ +local utl = require "luci.util" + +local sys = require "luci.sys" +local zones = require "luci.sys.zoneinfo" +local fs = require "nixio.fs" +local conf = require "luci.config" + +m = Map("blockport", translate("Port Blocking"), translate("Block traffic using specific ports")) + +m.on_after_save = function(self) + luci.sys.call("/usr/lib/blockport/blockport.sh &") +end + +s = m:section(TypedSection, "port", translate("Block Port List")) +s.anonymous = true +s.addremove = false + +s:option(DynamicList, "block", translate("Ports")) + + +return m \ No newline at end of file diff --git a/rooter/0optionalapps/ext-domain/Makefile b/rooter/0optionalapps/ext-domain/Makefile new file mode 100644 index 0000000..66e3d59 --- /dev/null +++ b/rooter/0optionalapps/ext-domain/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-domain +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-domain + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + DEPENDS:=+dnsmasq-full +ipset + TITLE:=Domain Filter + PKGARCH:=all +endef + +define Package/ext-domain/description + Helper scripts to install Domain Filter on ROOter +endef + + +define Build/Compile +endef + +define Package/ext-domain/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-domain)) diff --git a/rooter/0optionalapps/ext-domain/files/etc/config/filter b/rooter/0optionalapps/ext-domain/files/etc/config/filter new file mode 100644 index 0000000..5eb7a3b --- /dev/null +++ b/rooter/0optionalapps/ext-domain/files/etc/config/filter @@ -0,0 +1 @@ +config filter filter diff --git a/rooter/0optionalapps/ext-domain/files/etc/init.d/domain b/rooter/0optionalapps/ext-domain/files/etc/init.d/domain new file mode 100644 index 0000000..2e99572 --- /dev/null +++ b/rooter/0optionalapps/ext-domain/files/etc/init.d/domain @@ -0,0 +1,46 @@ +#!/bin/sh /etc/rc.common + +START=99 + +log() { + logger -t "Domain Filter " "$@" +} + +start() +{ + ff=$(uci -q get firewall.filter) + if [ -z $ff ]; then + uci set firewall.filter="ipset" + uci set firewall.filter.name="filter" + uci set firewall.filter.family="ipv4" + uci set firewall.filter.storage="hash" + uci set firewall.filter.match="ip" + uci set firewall.filter6="ipset" + uci set firewall.filter6.name="filter6" + uci set firewall.filter6.family="ipv6" + uci set firewall.filter6.storage="hash" + uci set firewall.filter6.match="ip" + + # Filter LAN client traffic with IP sets + uci set firewall.filter_fwd="rule" + uci set firewall.filter_fwd.name="Filter-IPset-DNS-Forward" + uci set firewall.filter_fwd.src="lan" + uci set firewall.filter_fwd.dest="wan" + uci set firewall.filter_fwd.ipset="filter dest" + uci set firewall.filter_fwd.family="ipv4" + uci set firewall.filter_fwd.proto="all" + uci set firewall.filter_fwd.target="REJECT" + uci set firewall.filter6_fwd="rule" + uci set firewall.filter6_fwd.name="Filter6-IPset-DNS-Forward" + uci set firewall.filter6_fwd.src="lan" + uci set firewall.filter6_fwd.dest="wan" + uci set firewall.filter6_fwd.ipset="filter6 dest" + uci set firewall.filter6_fwd.family="ipv6" + uci set firewall.filter6_fwd.proto="all" + uci set firewall.filter6_fwd.target="REJECT" + + uci commit firewall + /etc/init.d/firewall restart + fi + /usr/lib/domain/filter.sh +} \ No newline at end of file diff --git a/rooter/0optionalapps/ext-domain/files/usr/lib/domain/filter.sh b/rooter/0optionalapps/ext-domain/files/usr/lib/domain/filter.sh new file mode 100644 index 0000000..1bb349c --- /dev/null +++ b/rooter/0optionalapps/ext-domain/files/usr/lib/domain/filter.sh @@ -0,0 +1,26 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Domain Filter " "$@" +} + +handle_ipset() { + local ips=$1 + uci add_list dhcp.@dnsmasq[0].ipset='/'$ips'/filter,filter6' +} + +do_ipset() { + local config=$1 + local ipset + + config_list_foreach "$config" ipset handle_ipset +} + +sleep 3 + +uci -q delete dhcp.@dnsmasq[0].ipset +config_load filter +config_foreach do_ipset filter +uci commit dhcp +/etc/init.d/dnsmasq restart \ No newline at end of file diff --git a/rooter/0optionalapps/ext-domain/files/usr/lib/lua/luci/controller/domain.lua b/rooter/0optionalapps/ext-domain/files/usr/lib/lua/luci/controller/domain.lua new file mode 100644 index 0000000..5bca115 --- /dev/null +++ b/rooter/0optionalapps/ext-domain/files/usr/lib/lua/luci/controller/domain.lua @@ -0,0 +1,15 @@ +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.domain", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local lock = luci.model.uci.cursor():get("custom", "menu", "full") + --if lock == "1" then + local page + page = entry({"admin", "adminmenu", "domain"}, cbi("domainfltr"), _(translate("Domain Filter")), 9) + page.dependent = true + --end +end diff --git a/rooter/0optionalapps/ext-domain/files/usr/lib/lua/luci/model/cbi/domainfltr.lua b/rooter/0optionalapps/ext-domain/files/usr/lib/lua/luci/model/cbi/domainfltr.lua new file mode 100644 index 0000000..9c898e5 --- /dev/null +++ b/rooter/0optionalapps/ext-domain/files/usr/lib/lua/luci/model/cbi/domainfltr.lua @@ -0,0 +1,21 @@ +local utl = require "luci.util" + +local sys = require "luci.sys" +local zones = require "luci.sys.zoneinfo" +local fs = require "nixio.fs" +local conf = require "luci.config" + +m = Map("filter", translate("Domain Filter"), translate("Block traffic to specified URLs")) + +m.on_after_save = function(self) + luci.sys.call("/usr/lib/domain/filter.sh &") +end + +s = m:section(TypedSection, "filter", translate("Block List")) +s.anonymous = true +s.addremove = false + +s:option(DynamicList, "ipset", translate("Domain URLs")) + + +return m \ No newline at end of file diff --git a/rooter/0optionalapps/ext-menu/Makefile b/rooter/0optionalapps/ext-menu/Makefile new file mode 100644 index 0000000..0dee3f0 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-menu +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-menu + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + TITLE:=Menu Selection + PKGARCH:=all +endef + +define Package/ext-menu/description + Helper scripts to install Menu Selection on ROOter +endef + + +define Build/Compile +endef + +define Package/ext-menu/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-menu)) diff --git a/rooter/0optionalapps/ext-menu/files/etc/uci-defaults/63-menu b/rooter/0optionalapps/ext-menu/files/etc/uci-defaults/63-menu new file mode 100644 index 0000000..d5375bd --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/etc/uci-defaults/63-menu @@ -0,0 +1,10 @@ +#!/bin/sh + +fv=$(uci -q get custom.menu.full) +if [ $fv = "0" ]; then + fv="1" +else + fv="0" +fi + +/usr/lib/fullmenu/setmenu.sh $fv diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/firewall.lua b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/firewall.lua new file mode 100644 index 0000000..d761109 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/firewall.lua @@ -0,0 +1,28 @@ +module("luci.controller.firewall", package.seeall) + +function index() + entry({"admin", "network", "firewall"}, + alias("admin", "network", "firewall", "zones"), + _("Firewall"), 60) + + entry({"admin", "network", "firewall", "zones"}, + view("firewall/zones"), _("General Settings"), 10) + + entry({"admin", "network", "firewall", "forwards"}, + view("firewall/forwards"), _("Port Forwards"), 20) + + entry({"admin", "network", "firewall", "rules"}, + view("firewall/rules"), _("Traffic Rules"), 30) + + entry({"admin", "network", "firewall", "snats"}, + view("firewall/snats"), _("NAT Rules"), 40) + + entry({"admin", "network", "firewall", "custom"}, + view("firewall/custom"), _("Custom Rules"), 45).leaf = true + + if nixio.fs.access("/etc/config/modem") then + entry({"admin", "network", "firewall", "ttl"}, + cbi("firewall/ttlx"), + _("Custom TTL Settings"), 50).leaf = true + end +end diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/luci-mod-status.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/luci-mod-status.json new file mode 100644 index 0000000..0dcf6e8 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/luci-mod-status.json @@ -0,0 +1,103 @@ +{ + "admin/status/overview": { + "title": "Overview", + "order": 1, + "action": { + "type": "template", + "path": "admin_status/index" + } + }, + + "admin/status/iptables": { + "title": "Firewall", + "order": 2, + "action": { + "type": "view", + "path": "status/iptables" + } + }, + + "admin/status/routes": { + "title": "Routes", + "order": 3, + "action": { + "type": "view", + "path": "status/routes" + } + }, + + "admin/status/syslog": { + "title": "System Log", + "order": 4, + "action": { + "type": "view", + "path": "status/syslog" + } + }, + + "admin/status/dmesg": { + "title": "Kernel Log", + "order": 5, + "action": { + "type": "view", + "path": "status/dmesg" + } + }, + + "admin/status/processes": { + "title": "Processes", + "order": 6, + "action": { + "type": "view", + "path": "status/processes" + } + }, + + "admin/status/realtime": { + "title": "Realtime Graphs", + "order": 7, + "action": { + "type": "alias", + "path": "admin/status/realtime/load" + } + }, + + "admin/status/realtime/load": { + "title": "Load", + "order": 1, + "action": { + "type": "view", + "path": "status/load" + } + }, + + "admin/status/realtime/bandwidth": { + "title": "Traffic", + "order": 2, + "action": { + "type": "view", + "path": "status/bandwidth" + } + }, + + "admin/status/realtime/wireless": { + "title": "Wireless", + "order": 3, + "action": { + "type": "view", + "path": "status/wireless" + }, + "depends": { + "uci": { "wireless": { "@wifi-device": true } } + } + }, + + "admin/status/realtime/connections": { + "title": "Connections", + "order": 4, + "action": { + "type": "view", + "path": "status/connections" + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/luci-mod-system.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/luci-mod-system.json new file mode 100644 index 0000000..ef21d6e --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/luci-mod-system.json @@ -0,0 +1,111 @@ +{ + "admin/system/system": { + "title": "System", + "order": 1, + "action": { + "type": "view", + "path": "system/system" + } + }, + + "admin/system/admin": { + "title": "Administration", + "order": 2, + "action": { + "type": "firstchild" + } + }, + + "admin/system/admin/password": { + "title": "Router Password", + "order": 1, + "action": { + "type": "view", + "path": "system/password" + } + }, + + "admin/system/admin/dropbear": { + "title": "SSH Access", + "order": 2, + "action": { + "type": "view", + "path": "system/dropbear" + }, + "depends": { + "fs": { "/usr/sbin/dropbear": "executable" } + } + }, + + "admin/system/admin/sshkeys": { + "title": "SSH-Keys", + "order": 3, + "action": { + "type": "view", + "path": "system/sshkeys" + }, + "depends": { + "fs": { "/usr/sbin/dropbear": "executable" } + } + }, + + "admin/system/startup": { + "title": "Startup", + "order": 45, + "action": { + "type": "view", + "path": "system/startup" + } + }, + + "admin/system/crontab": { + "title": "Scheduled Tasks", + "order": 46, + "action": { + "type": "view", + "path": "system/crontab" + } + }, + + "admin/system/mounts": { + "title": "Mount Points", + "order": 50, + "action": { + "type": "view", + "path": "system/mounts" + }, + "depends": { + "fs": { "/sbin/block": "executable" } + } + }, + + "admin/system/leds": { + "title": "LED Configuration", + "order": 60, + "action": { + "type": "view", + "path": "system/leds" + }, + "depends": { + "fs": { "/sys/class/leds": "directory" } + } + }, + + "admin/system/flash": { + "title": "Backup / Flash Firmware", + "order": 70, + "action": { + "type": "view", + "path": "system/flash" + } + }, + + "admin/system/reboot": { + "title": "Reboot", + "order": 90, + "action": { + "type": "view", + "path": "system/reboot" + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/network.lua b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/network.lua new file mode 100644 index 0000000..b34ec4f --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/network.lua @@ -0,0 +1,44 @@ +-- Copyright 2008 Steven Barth +-- Copyright 2011-2018 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.admin.network", package.seeall) + +function index() + local page + +-- if page.inreq then + page = entry({"admin", "network", "switch"}, view("network/switch"), _("Switch"), 20) + page.uci_depends = { network = { ["@switch[0]"] = "switch" } } + + page = entry({"admin", "network", "wireless"}, view("network/wireless"), _('Wireless'), 15) + page.uci_depends = { wireless = { ["@wifi-device[0]"] = "wifi-device" } } + page.leaf = true + + page = entry({"admin", "network", "network"}, view("network/interfaces"), _("Interfaces"), 10) + page.leaf = true + page.subindex = true + + page = node("admin", "network", "dhcp") + page.uci_depends = { dhcp = true } + page.target = view("network/dhcp") + page.title = _("DHCP and DNS") + page.order = 30 + + page = node("admin", "network", "hosts") + page.uci_depends = { dhcp = true } + page.target = view("network/hosts") + page.title = _("Hostnames") + page.order = 40 + + page = node("admin", "network", "routes") + page.target = view("network/routes") + page.title = _("Static Routes") + page.order = 50 + + page = node("admin", "network", "diagnostics") + page.target = view("network/diagnostics") + page.title = _("Diagnostics") + page.order = 60 +-- end +end diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/opkg.lua b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/opkg.lua new file mode 100644 index 0000000..29c9a08 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full19/opkg.lua @@ -0,0 +1,117 @@ +-- Copyright 2018 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.opkg", package.seeall) + +function index() + entry({"admin", "system", "opkg"}, template("opkg"), _("Software"), 30) + entry({"admin", "system", "opkg", "list"}, call("action_list")).leaf = true + entry({"admin", "system", "opkg", "exec"}, post("action_exec")).leaf = true + entry({"admin", "system", "opkg", "statvfs"}, call("action_statvfs")).leaf = true + entry({"admin", "system", "opkg", "config"}, post_on({ data = true }, "action_config")).leaf = true +end + +function action_list(mode) + local util = require "luci.util" + local cmd + + if mode == "installed" then + cmd = { "/bin/cat", "/usr/lib/opkg/status" } + else + local lists_dir = nil + + local fd = io.popen([[sed -rne 's#^lists_dir \S+ (\S+)#\1#p' /etc/opkg.conf /etc/opkg/*.conf 2>/dev/null]], "r") + if fd then + lists_dir = fd:read("*l") + fd:close() + end + + if not lists_dir or #lists_dir == "" then + lists_dir = "/tmp/opkg-lists" + end + + cmd = { "/bin/sh", "-c", [[find %s -type f '!' -name '*.sig' | xargs -r gzip -cd]] % util.shellquote(lists_dir) } + end + + luci.http.prepare_content("text/plain; charset=utf-8") + luci.sys.process.exec(cmd, luci.http.write) +end + +function action_exec(command, package) + local sys = require "luci.sys" + local cmd = { "/bin/opkg", "--force-removal-of-dependent-packages" } + local pkg = luci.http.formvalue("package") + + if luci.http.formvalue("autoremove") == "true" then + cmd[#cmd + 1] = "--autoremove" + end + + if luci.http.formvalue("overwrite") == "true" then + cmd[#cmd + 1] = "--force-overwrite" + end + + cmd[#cmd + 1] = command + + if pkg then + cmd[#cmd + 1] = pkg + end + + luci.http.prepare_content("application/json") + luci.http.write_json(sys.process.exec(cmd, true, true)) +end + +function action_statvfs() + local fs = require "nixio.fs" + + luci.http.prepare_content("application/json") + luci.http.write_json(fs.statvfs("/") or {}) +end + +function action_config() + local fs = require "nixio.fs" + local js = require "luci.jsonc" + local data = luci.http.formvalue("data") + + if data then + data = js.parse(data) + + if not data then + luci.http.status(400, "Bad Request") + return + end + + local file, content + for file, content in pairs(data) do + if type(content) ~= "string" or + (file ~= "opkg.conf" and not file:match("^opkg/[^/]+%.conf$")) + then + luci.http.status(400, "Bad Request") + return + end + + local path = "/etc/%s" % file + if not fs.access(path, "w") then + luci.http.status(403, "Permission denied") + return + end + + fs.writefile(path, content:gsub("\r\n", "\n")) + end + + luci.http.status(204, "Saved") + else + local rv = { ["opkg.conf"] = fs.readfile("/etc/opkg.conf") } + local entries = fs.dir("/etc/opkg") + if entries then + local entry + for entry in entries do + if entry:match("%.conf$") then + rv["opkg/%s" % entry] = fs.readfile("/etc/opkg/%s" % entry) + end + end + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) + end +end diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-app-firewall.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-app-firewall.json new file mode 100644 index 0000000..4672a27 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-app-firewall.json @@ -0,0 +1,70 @@ +{ + "admin/network/firewall": { + "title": "Firewall", + "order": 60, + "action": { + "type": "alias", + "path": "admin/network/firewall/zones" + }, + "depends": { + "acl": [ "luci-app-firewall" ], + "fs": { "/sbin/fw3": "executable" }, + "uci": { "firewall": true } + } + }, + + "admin/network/firewall/zones": { + "title": "General Settings", + "order": 10, + "action": { + "type": "view", + "path": "firewall/zones" + } + }, + + "admin/network/firewall/forwards": { + "title": "Port Forwards", + "order": 20, + "action": { + "type": "view", + "path": "firewall/forwards" + } + }, + + "admin/network/firewall/rules": { + "title": "Traffic Rules", + "order": 30, + "action": { + "type": "view", + "path": "firewall/rules" + } + }, + + "admin/network/firewall/snats": { + "title": "NAT Rules", + "order": 40, + "action": { + "type": "view", + "path": "firewall/snats" + } + }, + + + "admin/network/firewall/custom": { + "title": "Custom Rules", + "order": 50, + "action": { + "type": "view", + "path": "firewall/custom" + } + }, + + "admin/network/firewall/customttl": { + "title": "Custom TTL Settings", + "order": 55, + "action": { + "type": "cbi", + "path": "firewall/ttlx" + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-app-opkg.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-app-opkg.json new file mode 100644 index 0000000..3d06a25 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-app-opkg.json @@ -0,0 +1,13 @@ +{ + "admin/system/opkg": { + "title": "Software", + "order": 30, + "action": { + "type": "view", + "path": "opkg" + }, + "depends": { + "acl": [ "luci-app-opkg" ] + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-network.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-network.json new file mode 100644 index 0000000..188c695 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-network.json @@ -0,0 +1,98 @@ +{ + "admin/network/switch": { + "title": "Switch", + "order": 20, + "action": { + "type": "view", + "path": "network/switch" + }, + "depends": { + "acl": [ "luci-mod-network-config" ], + "fs": { "/sbin/swconfig": "executable" }, + "uci": { "network": { "@switch": true } } + } + }, + + "admin/network/wireless": { + "title": "Wireless", + "order": 15, + "action": { + "type": "view", + "path": "network/wireless" + }, + "depends": { + "acl": [ "luci-mod-network-config" ], + "uci": { "wireless": { "@wifi-device": true } } + } + }, + + "admin/network/remote_addr/*": { + "action": { + "type": "call", + "module": "luci.controller.admin.network", + "function": "remote_addr" + } + }, + + "admin/network/network": { + "title": "Interfaces", + "order": 10, + "action": { + "type": "view", + "path": "network/interfaces" + }, + "depends": { + "acl": [ "luci-mod-network-config" ] + } + }, + + "admin/network/dhcp": { + "title": "DHCP and DNS", + "order": 30, + "action": { + "type": "view", + "path": "network/dhcp" + }, + "depends": { + "acl": [ "luci-mod-network-dhcp" ], + "uci": { "dhcp": true } + } + }, + + "admin/network/hosts": { + "title": "Hostnames", + "order": 40, + "action": { + "type": "view", + "path": "network/hosts" + }, + "depends": { + "acl": [ "luci-mod-network-dhcp" ], + "uci": { "dhcp": true } + } + }, + + "admin/network/routes": { + "title": "Static Routes", + "order": 50, + "action": { + "type": "view", + "path": "network/routes" + }, + "depends": { + "acl": [ "luci-mod-network-config" ] + } + }, + + "admin/network/diagnostics": { + "title": "Diagnostics", + "order": 60, + "action": { + "type": "view", + "path": "network/diagnostics" + }, + "depends": { + "acl": [ "luci-mod-network-diagnostics" ] + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-status.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-status.json new file mode 100644 index 0000000..0f066e6 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-status.json @@ -0,0 +1,137 @@ +{ + "admin/status/overview": { + "title": "Overview", + "order": 1, + "action": { + "type": "template", + "path": "admin_status/index" + }, + "depends": { + "acl": [ "luci-mod-status-index" ] + } + }, + + "admin/status/iptables": { + "title": "Firewall", + "order": 2, + "action": { + "type": "view", + "path": "status/iptables" + }, + "depends": { + "acl": [ "luci-mod-status-firewall" ] + } + }, + + "admin/status/routes": { + "title": "Routes", + "order": 3, + "action": { + "type": "view", + "path": "status/routes" + }, + "depends": { + "acl": [ "luci-mod-status-routes" ] + } + }, + + "admin/status/syslog": { + "title": "System Log", + "order": 4, + "action": { + "type": "view", + "path": "status/syslog" + }, + "depends": { + "acl": [ "luci-mod-status-logs" ] + } + }, + + "admin/status/dmesg": { + "title": "Kernel Log", + "order": 5, + "action": { + "type": "view", + "path": "status/dmesg" + }, + "depends": { + "acl": [ "luci-mod-status-logs" ] + } + }, + + "admin/status/processes": { + "title": "Processes", + "order": 6, + "action": { + "type": "view", + "path": "status/processes" + }, + "depends": { + "acl": [ "luci-mod-status-processes" ] + } + }, + + "admin/status/channel_analysis": { + "title": "Channel Analysis", + "order": 7, + "action": { + "type": "view", + "path": "status/channel_analysis" + }, + "depends": { + "acl": [ "luci-mod-status-channel_analysis" ], + "uci": { "wireless": { "@wifi-device": true } } + } + }, + + "admin/status/realtime": { + "title": "Realtime Graphs", + "order": 7, + "action": { + "type": "alias", + "path": "admin/status/realtime/load" + }, + "depends": { + "acl": [ "luci-mod-status-realtime" ] + } + }, + + "admin/status/realtime/load": { + "title": "Load", + "order": 1, + "action": { + "type": "view", + "path": "status/load" + } + }, + + "admin/status/realtime/bandwidth": { + "title": "Traffic", + "order": 2, + "action": { + "type": "view", + "path": "status/bandwidth" + } + }, + + "admin/status/realtime/wireless": { + "title": "Wireless", + "order": 3, + "action": { + "type": "view", + "path": "status/wireless" + }, + "depends": { + "uci": { "wireless": { "@wifi-device": true } } + } + }, + + "admin/status/realtime/connections": { + "title": "Connections", + "order": 4, + "action": { + "type": "view", + "path": "status/connections" + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-system.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-system.json new file mode 100644 index 0000000..4022e0c --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/full21/luci-mod-system.json @@ -0,0 +1,136 @@ +{ + "admin/system/system": { + "title": "System", + "order": 1, + "action": { + "type": "view", + "path": "system/system" + }, + "depends": { + "acl": [ "luci-mod-system-config" ] + } + }, + + "admin/system/admin": { + "title": "Administration", + "order": 2, + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ "luci-mod-system-config", "luci-mod-system-ssh" ] + } + }, + + "admin/system/admin/password": { + "title": "Router Password", + "order": 1, + "action": { + "type": "view", + "path": "system/password" + }, + "depends": { + "acl": [ "luci-mod-system-config" ] + } + }, + + "admin/system/admin/dropbear": { + "title": "SSH Access", + "order": 2, + "action": { + "type": "view", + "path": "system/dropbear" + }, + "depends": { + "acl": [ "luci-mod-system-ssh" ], + "fs": { "/usr/sbin/dropbear": "executable" } + } + }, + + "admin/system/admin/sshkeys": { + "title": "SSH-Keys", + "order": 3, + "action": { + "type": "view", + "path": "system/sshkeys" + }, + "depends": { + "acl": [ "luci-mod-system-ssh" ], + "fs": { "/usr/sbin/dropbear": "executable" } + } + }, + + "admin/system/startup": { + "title": "Startup", + "order": 45, + "action": { + "type": "view", + "path": "system/startup" + }, + "depends": { + "acl": [ "luci-mod-system-init" ] + } + }, + + "admin/system/crontab": { + "title": "Scheduled Tasks", + "order": 46, + "action": { + "type": "view", + "path": "system/crontab" + }, + "depends": { + "acl": [ "luci-mod-system-cron" ] + } + }, + + "admin/system/mounts": { + "title": "Mount Points", + "order": 50, + "action": { + "type": "view", + "path": "system/mounts" + }, + "depends": { + "acl": [ "luci-mod-system-mounts" ], + "fs": { "/sbin/block": "executable" } + } + }, + + "admin/system/leds": { + "title": "LED Configuration", + "order": 60, + "action": { + "type": "view", + "path": "system/leds" + }, + "depends": { + "acl": [ "luci-mod-system-config" ], + "fs": { "/sys/class/leds": "directory" } + } + }, + + "admin/system/flash": { + "title": "Backup / Flash Firmware", + "order": 70, + "action": { + "type": "view", + "path": "system/flash" + }, + "depends": { + "acl": [ "luci-mod-system-flash" ] + } + }, + + "admin/system/reboot": { + "title": "Reboot", + "order": 90, + "action": { + "type": "view", + "path": "system/reboot" + }, + "depends": { + "acl": [ "luci-mod-system-reboot" ] + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/firewall.lua b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/firewall.lua new file mode 100644 index 0000000..d761109 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/firewall.lua @@ -0,0 +1,28 @@ +module("luci.controller.firewall", package.seeall) + +function index() + entry({"admin", "network", "firewall"}, + alias("admin", "network", "firewall", "zones"), + _("Firewall"), 60) + + entry({"admin", "network", "firewall", "zones"}, + view("firewall/zones"), _("General Settings"), 10) + + entry({"admin", "network", "firewall", "forwards"}, + view("firewall/forwards"), _("Port Forwards"), 20) + + entry({"admin", "network", "firewall", "rules"}, + view("firewall/rules"), _("Traffic Rules"), 30) + + entry({"admin", "network", "firewall", "snats"}, + view("firewall/snats"), _("NAT Rules"), 40) + + entry({"admin", "network", "firewall", "custom"}, + view("firewall/custom"), _("Custom Rules"), 45).leaf = true + + if nixio.fs.access("/etc/config/modem") then + entry({"admin", "network", "firewall", "ttl"}, + cbi("firewall/ttlx"), + _("Custom TTL Settings"), 50).leaf = true + end +end diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/luci-mod-status.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/luci-mod-status.json new file mode 100644 index 0000000..7e664bf --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/luci-mod-status.json @@ -0,0 +1,19 @@ +{ + "admin/status/overview": { + "title": "Overview", + "order": 1, + "action": { + "type": "template", + "path": "admin_status/index" + } + }, + + "admin/status/syslog": { + "title": "System Log", + "order": 4, + "action": { + "type": "view", + "path": "status/syslog" + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/luci-mod-system.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/luci-mod-system.json new file mode 100644 index 0000000..f220775 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/luci-mod-system.json @@ -0,0 +1,45 @@ +{ + "admin/system/system": { + "title": "System", + "order": 1, + "action": { + "type": "view", + "path": "system/system" + } + }, + + "admin/system/admin": { + "title": "Administration", + "order": 2, + "action": { + "type": "firstchild" + } + }, + + "admin/system/admin/password": { + "title": "Router Password", + "order": 1, + "action": { + "type": "view", + "path": "system/password" + } + }, + + "admin/system/flash": { + "title": "Flash Firmware", + "order": 70, + "action": { + "type": "view", + "path": "system/flash" + } + }, + + "admin/system/reboot": { + "title": "Reboot", + "order": 90, + "action": { + "type": "view", + "path": "system/reboot" + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/network.lua b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/network.lua new file mode 100644 index 0000000..b34ec4f --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/network.lua @@ -0,0 +1,44 @@ +-- Copyright 2008 Steven Barth +-- Copyright 2011-2018 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.admin.network", package.seeall) + +function index() + local page + +-- if page.inreq then + page = entry({"admin", "network", "switch"}, view("network/switch"), _("Switch"), 20) + page.uci_depends = { network = { ["@switch[0]"] = "switch" } } + + page = entry({"admin", "network", "wireless"}, view("network/wireless"), _('Wireless'), 15) + page.uci_depends = { wireless = { ["@wifi-device[0]"] = "wifi-device" } } + page.leaf = true + + page = entry({"admin", "network", "network"}, view("network/interfaces"), _("Interfaces"), 10) + page.leaf = true + page.subindex = true + + page = node("admin", "network", "dhcp") + page.uci_depends = { dhcp = true } + page.target = view("network/dhcp") + page.title = _("DHCP and DNS") + page.order = 30 + + page = node("admin", "network", "hosts") + page.uci_depends = { dhcp = true } + page.target = view("network/hosts") + page.title = _("Hostnames") + page.order = 40 + + page = node("admin", "network", "routes") + page.target = view("network/routes") + page.title = _("Static Routes") + page.order = 50 + + page = node("admin", "network", "diagnostics") + page.target = view("network/diagnostics") + page.title = _("Diagnostics") + page.order = 60 +-- end +end diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/opkg.lua b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/opkg.lua new file mode 100644 index 0000000..29c9a08 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited19/opkg.lua @@ -0,0 +1,117 @@ +-- Copyright 2018 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.opkg", package.seeall) + +function index() + entry({"admin", "system", "opkg"}, template("opkg"), _("Software"), 30) + entry({"admin", "system", "opkg", "list"}, call("action_list")).leaf = true + entry({"admin", "system", "opkg", "exec"}, post("action_exec")).leaf = true + entry({"admin", "system", "opkg", "statvfs"}, call("action_statvfs")).leaf = true + entry({"admin", "system", "opkg", "config"}, post_on({ data = true }, "action_config")).leaf = true +end + +function action_list(mode) + local util = require "luci.util" + local cmd + + if mode == "installed" then + cmd = { "/bin/cat", "/usr/lib/opkg/status" } + else + local lists_dir = nil + + local fd = io.popen([[sed -rne 's#^lists_dir \S+ (\S+)#\1#p' /etc/opkg.conf /etc/opkg/*.conf 2>/dev/null]], "r") + if fd then + lists_dir = fd:read("*l") + fd:close() + end + + if not lists_dir or #lists_dir == "" then + lists_dir = "/tmp/opkg-lists" + end + + cmd = { "/bin/sh", "-c", [[find %s -type f '!' -name '*.sig' | xargs -r gzip -cd]] % util.shellquote(lists_dir) } + end + + luci.http.prepare_content("text/plain; charset=utf-8") + luci.sys.process.exec(cmd, luci.http.write) +end + +function action_exec(command, package) + local sys = require "luci.sys" + local cmd = { "/bin/opkg", "--force-removal-of-dependent-packages" } + local pkg = luci.http.formvalue("package") + + if luci.http.formvalue("autoremove") == "true" then + cmd[#cmd + 1] = "--autoremove" + end + + if luci.http.formvalue("overwrite") == "true" then + cmd[#cmd + 1] = "--force-overwrite" + end + + cmd[#cmd + 1] = command + + if pkg then + cmd[#cmd + 1] = pkg + end + + luci.http.prepare_content("application/json") + luci.http.write_json(sys.process.exec(cmd, true, true)) +end + +function action_statvfs() + local fs = require "nixio.fs" + + luci.http.prepare_content("application/json") + luci.http.write_json(fs.statvfs("/") or {}) +end + +function action_config() + local fs = require "nixio.fs" + local js = require "luci.jsonc" + local data = luci.http.formvalue("data") + + if data then + data = js.parse(data) + + if not data then + luci.http.status(400, "Bad Request") + return + end + + local file, content + for file, content in pairs(data) do + if type(content) ~= "string" or + (file ~= "opkg.conf" and not file:match("^opkg/[^/]+%.conf$")) + then + luci.http.status(400, "Bad Request") + return + end + + local path = "/etc/%s" % file + if not fs.access(path, "w") then + luci.http.status(403, "Permission denied") + return + end + + fs.writefile(path, content:gsub("\r\n", "\n")) + end + + luci.http.status(204, "Saved") + else + local rv = { ["opkg.conf"] = fs.readfile("/etc/opkg.conf") } + local entries = fs.dir("/etc/opkg") + if entries then + local entry + for entry in entries do + if entry:match("%.conf$") then + rv["opkg/%s" % entry] = fs.readfile("/etc/opkg/%s" % entry) + end + end + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) + end +end diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-app-firewall.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-app-firewall.json new file mode 100644 index 0000000..4672a27 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-app-firewall.json @@ -0,0 +1,70 @@ +{ + "admin/network/firewall": { + "title": "Firewall", + "order": 60, + "action": { + "type": "alias", + "path": "admin/network/firewall/zones" + }, + "depends": { + "acl": [ "luci-app-firewall" ], + "fs": { "/sbin/fw3": "executable" }, + "uci": { "firewall": true } + } + }, + + "admin/network/firewall/zones": { + "title": "General Settings", + "order": 10, + "action": { + "type": "view", + "path": "firewall/zones" + } + }, + + "admin/network/firewall/forwards": { + "title": "Port Forwards", + "order": 20, + "action": { + "type": "view", + "path": "firewall/forwards" + } + }, + + "admin/network/firewall/rules": { + "title": "Traffic Rules", + "order": 30, + "action": { + "type": "view", + "path": "firewall/rules" + } + }, + + "admin/network/firewall/snats": { + "title": "NAT Rules", + "order": 40, + "action": { + "type": "view", + "path": "firewall/snats" + } + }, + + + "admin/network/firewall/custom": { + "title": "Custom Rules", + "order": 50, + "action": { + "type": "view", + "path": "firewall/custom" + } + }, + + "admin/network/firewall/customttl": { + "title": "Custom TTL Settings", + "order": 55, + "action": { + "type": "cbi", + "path": "firewall/ttlx" + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-network.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-network.json new file mode 100644 index 0000000..188c695 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-network.json @@ -0,0 +1,98 @@ +{ + "admin/network/switch": { + "title": "Switch", + "order": 20, + "action": { + "type": "view", + "path": "network/switch" + }, + "depends": { + "acl": [ "luci-mod-network-config" ], + "fs": { "/sbin/swconfig": "executable" }, + "uci": { "network": { "@switch": true } } + } + }, + + "admin/network/wireless": { + "title": "Wireless", + "order": 15, + "action": { + "type": "view", + "path": "network/wireless" + }, + "depends": { + "acl": [ "luci-mod-network-config" ], + "uci": { "wireless": { "@wifi-device": true } } + } + }, + + "admin/network/remote_addr/*": { + "action": { + "type": "call", + "module": "luci.controller.admin.network", + "function": "remote_addr" + } + }, + + "admin/network/network": { + "title": "Interfaces", + "order": 10, + "action": { + "type": "view", + "path": "network/interfaces" + }, + "depends": { + "acl": [ "luci-mod-network-config" ] + } + }, + + "admin/network/dhcp": { + "title": "DHCP and DNS", + "order": 30, + "action": { + "type": "view", + "path": "network/dhcp" + }, + "depends": { + "acl": [ "luci-mod-network-dhcp" ], + "uci": { "dhcp": true } + } + }, + + "admin/network/hosts": { + "title": "Hostnames", + "order": 40, + "action": { + "type": "view", + "path": "network/hosts" + }, + "depends": { + "acl": [ "luci-mod-network-dhcp" ], + "uci": { "dhcp": true } + } + }, + + "admin/network/routes": { + "title": "Static Routes", + "order": 50, + "action": { + "type": "view", + "path": "network/routes" + }, + "depends": { + "acl": [ "luci-mod-network-config" ] + } + }, + + "admin/network/diagnostics": { + "title": "Diagnostics", + "order": 60, + "action": { + "type": "view", + "path": "network/diagnostics" + }, + "depends": { + "acl": [ "luci-mod-network-diagnostics" ] + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-status.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-status.json new file mode 100644 index 0000000..5beffdd --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-status.json @@ -0,0 +1,38 @@ +{ + "admin/status/overview": { + "title": "Overview", + "order": 1, + "action": { + "type": "template", + "path": "admin_status/index" + }, + "depends": { + "acl": [ "luci-mod-status-index" ] + } + }, + + "admin/status/syslog": { + "title": "System Log", + "order": 4, + "action": { + "type": "view", + "path": "status/syslog" + }, + "depends": { + "acl": [ "luci-mod-status-logs" ] + } + }, + + "admin/status/channel_analysis": { + "title": "Wifi Channel Analysis", + "order": 7, + "action": { + "type": "view", + "path": "status/channel_analysis" + }, + "depends": { + "acl": [ "luci-mod-status-channel_analysis" ], + "uci": { "wireless": { "@wifi-device": true } } + } + }, +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-system.json b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-system.json new file mode 100644 index 0000000..7ab8bed --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/limited21/luci-mod-system.json @@ -0,0 +1,60 @@ +{ + "admin/system/system": { + "title": "System", + "order": 1, + "action": { + "type": "view", + "path": "system/system" + }, + "depends": { + "acl": [ "luci-mod-system-config" ] + } + }, + + "admin/system/admin": { + "title": "Administration", + "order": 2, + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ "luci-mod-system-config", "luci-mod-system-ssh" ] + } + }, + + "admin/system/admin/password": { + "title": "Router Password", + "order": 1, + "action": { + "type": "view", + "path": "system/password" + }, + "depends": { + "acl": [ "luci-mod-system-config" ] + } + }, + + "admin/system/flash": { + "title": "Flash Firmware", + "order": 70, + "action": { + "type": "view", + "path": "system/flash" + }, + "depends": { + "acl": [ "luci-mod-system-flash" ] + } + }, + + "admin/system/reboot": { + "title": "Reboot", + "order": 90, + "action": { + "type": "view", + "path": "system/reboot" + }, + "depends": { + "acl": [ "luci-mod-system-reboot" ] + } + } +} diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/setmenu.sh b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/setmenu.sh new file mode 100644 index 0000000..fd5bc31 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/fullmenu/setmenu.sh @@ -0,0 +1,34 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Menu Change" "$@" +} + +full=$1 +source /etc/openwrt_release +twone=$(echo "$DISTRIB_RELEASE" | grep "21.02") + +if [ $full = "0" ]; then + fv="1" + if [ ! -z "$twone" ]; then # 21.02 + cp /usr/lib/fullmenu/full21/luci-mod-status.json /usr/share/luci/menu.d + cp /usr/lib/fullmenu/full21/luci-mod-system.json /usr/share/luci/menu.d + cp /usr/lib/fullmenu/full21/luci-app-opkg.json /usr/share/luci/menu.d + else # 19.07.6 + cp /usr/lib/fullmenu/full19/luci-mod-status.json /usr/share/luci/menu.d + cp /usr/lib/fullmenu/full19/luci-mod-system.json /usr/share/luci/menu.d + fi +else + fv="0" + if [ ! -z "$twone" ]; then # 21.02 + cp /usr/lib/fullmenu/limited21/luci-mod-status.json /usr/share/luci/menu.d + cp /usr/lib/fullmenu/limited21/luci-mod-system.json /usr/share/luci/menu.d + rm -f /usr/share/luci/menu.d/luci-app-opkg.json + else # 19.07.6 + cp /usr/lib/fullmenu/limited19/luci-mod-status.json /usr/share/luci/menu.d + cp /usr/lib/fullmenu/limited19/luci-mod-system.json /usr/share/luci/menu.d + fi +fi +uci set custom.menu.full=$fv +uci commit custom \ No newline at end of file diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/lua/luci/controller/fullmenu.lua b/rooter/0optionalapps/ext-menu/files/usr/lib/lua/luci/controller/fullmenu.lua new file mode 100644 index 0000000..20d1494 --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/lua/luci/controller/fullmenu.lua @@ -0,0 +1,28 @@ +module("luci.controller.fullmenu", package.seeall) +function index() + local fs = require "nixio.fs" + local page + page = entry({"admin", "system", "fullmenu"}, template("fullmenu/fullmenu"), "Menu Selection", 96) + page.dependent = true + + entry({"admin", "system", "getmenu"}, call("action_getmenu")) + entry({"admin", "system", "setmenu"}, call("action_setmenu")) + +end + +function action_getmenu() + local rv = {} + id = luci.model.uci.cursor():get("custom", "menu", "full") + rv["full"] = id + password = luci.model.uci.cursor():get("custom", "menu", "password") + rv["password"] = password + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_setmenu() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/fullmenu/setmenu.sh " .. set) + +end \ No newline at end of file diff --git a/rooter/0optionalapps/ext-menu/files/usr/lib/lua/luci/view/fullmenu/fullmenu.htm b/rooter/0optionalapps/ext-menu/files/usr/lib/lua/luci/view/fullmenu/fullmenu.htm new file mode 100644 index 0000000..a08e06d --- /dev/null +++ b/rooter/0optionalapps/ext-menu/files/usr/lib/lua/luci/view/fullmenu/fullmenu.htm @@ -0,0 +1,166 @@ +<%+header%> +<% +local sys = require "luci.sys" +local utl = require "luci.util" +local fs = require "nixio.fs" + +function showicon(lck) + if lck == 0 then + return resource .. "/icons/unlock1.png" + else + return resource .. "/icons/lock1.png" + end +end + +-%> + + + +
                +
                +

                <%:Menu Selection%>

                +
                + + + + +
                + + + + + + + + + + + + + + + + + + + + + + +
                <%:Current Menu is Limited.%>
                <%:You must enter a password to change to the full Menu.%>
                + + + + + + + + + + + + + + +
                <%:Current Menu is Full.%>
                <%:You must enter a password to change to the limited Menu.%>
                + +
                + +
                +
                +<%+footer%> \ No newline at end of file diff --git a/rooter/0optionalapps/ext-rspeedtest/Makefile b/rooter/0optionalapps/ext-rspeedtest/Makefile new file mode 100644 index 0000000..5dee477 --- /dev/null +++ b/rooter/0optionalapps/ext-rspeedtest/Makefile @@ -0,0 +1,34 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-rspeedtest +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-rspeedtest + SECTION:=utils + CATEGORY:=ROOter + DEPENDS:=+httping +curl +coreutils +coreutils-date +speedtestpp + SUBMENU:=Optional Applications + TITLE:=support for ROOter SpeedTest + PKGARCH:=all +endef + +define Package/ext-rspeedtest/description + Helper scripts to enable ROOter SpeedTest +endef + + +define Build/Compile +endef + +define Package/ext-rspeedtest/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,ext-rspeedtest)) diff --git a/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/lua/luci/controller/rspeedtest.lua b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/lua/luci/controller/rspeedtest.lua new file mode 100644 index 0000000..6ac5628 --- /dev/null +++ b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/lua/luci/controller/rspeedtest.lua @@ -0,0 +1,79 @@ +module("luci.controller.rspeedtest", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + page = entry({"admin", "speed", "rspeedtest"}, template("speedtest/rspeedtest"), translate("SpeedTest by Ookla"), 72) + page.dependent = true + + entry({"admin", "speed", "closeserver"}, call("action_closeserver")) + entry({"admin", "speed", "stoptest"}, call("action_stoptest")) + entry({"admin", "speed", "getspeed"}, call("action_getspeed")) + entry({"admin", "speed", "getspeeddata"}, call("action_getspeeddata")) +end + +function action_closeserver() + local rv = {} + + os.execute("/usr/lib/speedtest/info.sh") + result = "/tmp/sinfo" + file = io.open(result, "r") + if file ~= nil then + rv["status"] = file:read("*line") + if rv["status"] ~= "0" then + rv["ip"] = file:read("*line") + rv["isp"] = file:read("*line") + rv["city"] = file:read("*line") + rv["prov"] = file:read("*line") + end + file:close() + else + rv["status"] = "0" + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_stoptest() + os.execute("/usr/lib/speedtest/stop.sh") +end + +function action_getspeed() + local rv = {} + + os.execute("/usr/lib/speedtest/getspeed.sh ") + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_getspeeddata() + local rv = {} + + result = "/tmp/getspeed" + file = io.open(result, "r") + if file ~= nil then + rv["dlsize"] = file:read("*line") + rv["dlelapse"] = file:read("*line") + rv["ulsize"] = file:read("*line") + rv["ulelapse"] = file:read("*line") + file:close() + else + rv["dlsize"] = "0" + rv["ulsize"] = "0" + end + result = "/tmp/spworking" + file = io.open(result, "r") + if file ~= nil then + rv["working"] = file:read("*line") + file:close() + else + rv["working"] = "0" + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end diff --git a/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/lua/luci/view/speedtest/rspeedtest.htm b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/lua/luci/view/speedtest/rspeedtest.htm new file mode 100644 index 0000000..a35eaa4 --- /dev/null +++ b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/lua/luci/view/speedtest/rspeedtest.htm @@ -0,0 +1,259 @@ +<%+header%> +<% + user_icon = resource .. "/img/user.png" + prov_icon = resource .. "/img/prov.png" + load_icon = resource .. "/icons/loading.gif" +%> + + + + +
                + +
                +

                <%:Speed Test by Ookla%>

                +
                <%:An Internet speed test that runs from the router%>
                + + + +
                + + + + + + +
                <%:***Finding Optimal Server***%>
                 
                + + + + + + + + + + +
                 
                 
                + + + + + + + + +
                 
                 
                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                 
                + + + + + + + + + + + + + + + + + + +
                + +
                + +<%+footer%> \ No newline at end of file diff --git a/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/closest.lua b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/closest.lua new file mode 100644 index 0000000..5544048 --- /dev/null +++ b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/closest.lua @@ -0,0 +1,62 @@ +#!/usr/bin/lua + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +ulat = arg[1] +ulon = arg[2] + +url = {} +slat = {} +slon = {} +city = {} +dist = {} +prov = {} + +radius = 6371 + +cnt = 0 +clos = 99999999.99 +index = 0 +file = io.open("/tmp/slist", "r") +if file ~= nil then + repeat + line = file:read("*line") + if line == nil then + break + end + cnt = cnt + 1 + s, e = line:find(" ") + if s ~= nil then + url[cnt] = trim(line:sub(0, s-1)) + cs, ce = line:find(" ", e+1) + slat[cnt] = trim(line:sub(e, cs-1)) + s, e = line:find(" ", ce+1) + slon[cnt] = trim(line:sub(ce, s-1)) + cs, ce = line:find("\"", e+1) + s, e = line:find("\"", ce+1) + city[cnt] = trim(line:sub(ce+1, s-1)) + prov[cnt] = trim(line:sub(e+1)) + + dlat = math.rad(slat[cnt] - ulat) + dlon = math.rad(slon[cnt] - ulon) + a = (math.sin(dlat / 2) * math.sin(dlat / 2) + math.cos(math.rad(ulat)) * math.cos(math.rad(slat[cnt])) * math.sin(dlon / 2) * math.sin(dlon / 2)) + c = 2 * math.atan(math.sqrt(a), math.sqrt(1 - a)) + dist[cnt] = radius * c + + if dist[cnt] < clos then + clos = dist[cnt] + index = cnt + end + end + until 1==0 + file:close() + tfile = io.open("/tmp/close", "w") + tfile:write("CURL=\"", url[index], "\"\n") + tfile:write("CITY=\"", city[index], "\"\n") + tfile:write("PROV=\"", prov[index], "\"") + tfile:close() +end + + diff --git a/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/getspeed.sh b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/getspeed.sh new file mode 100644 index 0000000..7583f5b --- /dev/null +++ b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/getspeed.sh @@ -0,0 +1,83 @@ +#!/bin/sh + +log() { + logger -t "Getspeed " "$@" +} + +fixspeed() { + sed 's/\(PROVIDER=[[:blank:]]*\)\(.*\)/\1'\''\2'\''/' /tmp/speed > /tmp/tspeed +} + +echo "0" > /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "1" > /tmp/spworking + +JITTER="" +LATENCY="" +DOWNLOAD_SPEED="" +UPLOAD_SPEED="" + +while IFS= read -r line +do + read -r line + read -r line + read -r line + read -r line + read -r line + break +done < /tmp/sinfo +url=${line:7:100} +url=$(echo $url" " | tr "/" ",") +url=$(echo "$url" | cut -d, -f1) +rm -f /tmp/speed +speedtest --test-server $url --output text > /tmp/speed & +while [ -z "$JITTER" ] +do + if [ -e /tmp/speed ]; then + fixspeed + if [ -e /tmp/tspeed ]; then + source /tmp/tspeed + fi + fi + sleep 1 +done +echo "$LATENCY" > /tmp/getspeed +echo "$JITTER" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "2" > /tmp/spworking + +while [ -z "$DOWNLOAD_SPEED" ] +do + if [ -e /tmp/speed ]; then + fixspeed + if [ -e /tmp/tspeed ]; then + source /tmp/tspeed + fi + fi + sleep 1 +done +echo "$LATENCY" > /tmp/getspeed +echo "$JITTER" >> /tmp/getspeed +echo "$DOWNLOAD_SPEED" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "3" > /tmp/spworking + +while [ -z "$UPLOAD_SPEED" ] +do + if [ -e /tmp/speed ]; then + fixspeed + if [ -e /tmp/tspeed ]; then + source /tmp/tspeed + fi + fi + sleep 1 +done +echo "$LATENCY" > /tmp/getspeed +echo "$JITTER" >> /tmp/getspeed +echo "$DOWNLOAD_SPEED" >> /tmp/getspeed +echo "$UPLOAD_SPEED" >> /tmp/getspeed +echo "0" > /tmp/spworking + diff --git a/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/info.sh b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/info.sh new file mode 100644 index 0000000..1232246 --- /dev/null +++ b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/info.sh @@ -0,0 +1,75 @@ +#!/bin/sh + +killprocess() { + proc=$1 + PID=$(ps |grep "$proc" | grep -v grep |head -n 1 | awk '{print $1}') + if [ ! -z $PID ]; then + kill -9 $PID + fi +} + +killprocess "speedtest --test-server" +killprocess "/speedtest/closest.lua" +killprocess "/speedtest/getspeed.sh" +killprocess "/speedtest/servers.lua" + +rm -f /tmp/speed +rm -f /tmp/sinfo +rm -f /tmp/close +rm -f /tmp/getspeed +rm -f /tmp/jpg +rm -f /tmp/pinfo +rm -f /tmp/sinfo +rm -f /tmp/slist +echo "0" > /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" > /tmp/spworking +wget -q -O /tmp/client http://speedtest.net/speedtest-config.php +if [ $? = "0" ]; then + RAW=$(cat /tmp/client) + clid=$(echo $RAW" " | grep -o " " | tr -d '"' | tr " " "," | tr "/" "," | tr "=" ",") + ip=$(echo $clid | cut -d, -f3) + ulat=$(echo $clid | cut -d, -f5) + ulon=$(echo $clid | cut -d, -f7) + isp=$(echo $clid | cut -d, -f9) + rm -f /tmp/client + echo "1" > /tmp/sinfo + echo "$ip" >> /tmp/sinfo + echo "$isp" >> /tmp/sinfo + + wget -q -O /tmp/servers http://www.speedtest.net/speedtest-servers-static.php + if [ $? != "0" ]; then + wget -q -O /tmp/servers http://c.speedtest.net/speedtest-servers.php + if [ $? != "0" ]; then + echo "0" > /tmp/sinfo + exit 0 + fi + fi + rm -f /tmp/slist + while IFS= read -r line + do + read -r line + /usr/lib/speedtest/servers.lua "$line" + if [ -e /tmp/server ]; then + source /tmp/server + echo "$URL $LAT $LON "\""$NAME"\"" $SPONSOR" >> /tmp/slist + rm -f /tmp/server + fi + done < /tmp/servers + rm -f /tmp/servers + + /usr/lib/speedtest/closest.lua $ulat $ulon + source /tmp/close + echo "$CITY" >> /tmp/sinfo + echo "$PROV" >> /tmp/sinfo + echo "$CURL" >> /tmp/sinfo + rm -f /tmp/slist + rm -f /tmp/close +else + echo "0" > /tmp/sinfo + exit 0 +fi + diff --git a/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/ping.sh b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/ping.sh new file mode 100644 index 0000000..7ec502c --- /dev/null +++ b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/ping.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +rm -f /tmp/pinfo + +echo "0" > /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "1" > /tmp/spworking +while IFS= read -r line +do + read -r line + read -r line + read -r line + read -r line + read -r line + break +done < /tmp/sinfo + +hp=$(httping -c 3 $line) +pingg=$(echo $hp" " | grep -o "round-trip .\+ ms " | tr " " "," | tr "/" ",") +latency=$(echo $pingg | cut -d, -f7) + +echo "$latency" > /tmp/pinfo +echo "2" > /tmp/spworking + diff --git a/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/servers.lua b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/servers.lua new file mode 100644 index 0000000..abc3962 --- /dev/null +++ b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/servers.lua @@ -0,0 +1,46 @@ +#!/usr/bin/lua + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +line = arg[1] +if line == nil then + return +end + +s, e = line:find("url=\"") +if s ~= nil then + cs, ce = line:find("\"", e+1) + url = trim(line:sub(e+1, cs-1)) +else + return +end +s, e = line:find("lat=\"") +if s ~= nil then + cs, ce = line:find("\"", e+1) + lat = trim(line:sub(e+1, cs-1)) +end +s, e = line:find("lon=\"") +if s ~= nil then + cs, ce = line:find("\"", e+1) + lon = trim(line:sub(e+1, cs-1)) +end +s, e = line:find("name=\"") +if s ~= nil then + cs, ce = line:find("\"", e+1) + name = trim(line:sub(e+1, cs-1)) +end +s, e = line:find("sponsor=\"") +if s ~= nil then + cs, ce = line:find("\"", e+1) + sponsor = trim(line:sub(e+1, cs-1)) +end + +tfile = io.open("/tmp/server", "w") +tfile:write("URL=\"", url, "\"\n") +tfile:write("LAT=\"", lat, "\"\n") +tfile:write("LON=\"", lon, "\"\n") +tfile:write("NAME=\"", name, "\"\n") +tfile:write("SPONSOR=\"", sponsor, "\"") +tfile:close() \ No newline at end of file diff --git a/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/stop.sh b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/stop.sh new file mode 100644 index 0000000..c95dec0 --- /dev/null +++ b/rooter/0optionalapps/ext-rspeedtest/files/usr/lib/speedtest/stop.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +killprocess() { + proc=$1 + PID=$(pgrep -f "$proc") + if [ ! -z $PID ]; then + kill -9 $PID + fi +} + +killprocess "speedtest --test-server" +killprocess "/speedtest/closest.lua" +killprocess "/speedtest/getspeed.sh" +killprocess "/speedtest/servers.lua" + +flist="/tmp/speed /tmp/sinfo /tmp/close /tmp/getspeed /tmp/jpg /tmp/pinfo /tmp/sinfo /tmp/slist" + +for val in $flist; do + rm -f $val +done + +echo "0" > /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" >> /tmp/getspeed +echo "0" > /tmp/spworking + diff --git a/rooter/0optionalapps/ext-rspeedtest/files/www/luci-static/resources/img/prov.png b/rooter/0optionalapps/ext-rspeedtest/files/www/luci-static/resources/img/prov.png new file mode 100644 index 0000000000000000000000000000000000000000..715618c41900d9ebd5be760daa41acadfc2cd01f GIT binary patch literal 23789 zcmV($K;yrOP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3^glH@p+W&gQ~S^@zQ({eD7BE5rNexC!Hdw4`- zl}NX=TV}YMnJSe8-f-`ma6JF}f4#?l{nvkm+(JC=RBCQHpZvMo-D2k-_5A*Pe~0tl z|J{G$uiu5g|NQv_0!h{=O8)nSWl8|FK3tKM(02Kfiu| zO#Is&g}*-eZ@+lkeg5swA8Yr%tG@5^Jzc*uE0vF*hx+v>`(M0pu$0$+Tjs0q|HQw` z{%U+x9&xf`i`^W2%_AU{to9r3utE=Sc=q2jOm6XxPb~Z$<75x~S-nbZab9l0?N@kX zVH?(QRd!;sYZpI`zwagN&u#njW~hAf3cNA~E*5ylzrK$D^uzy`uiqDXUqv^Bv;JNy z?kg(O+=e^ne|Z&q5Z<3PO?!R!*YStkoPTWW#SW&u%#{c1=lCu$Qus@@uD#C}uS@5B zoZl{ovVJbW67kuIn+X>?aApKMRnUKwbWW$?Jc$o6P8+T9+_kPox-}2VCz5VyD z{p{-BcP;#5=l;8Z2+~L;!?A*Wi z?LX|=>f57SdxO+M*Yvzz4BInDN51Pj+8pJKt%On9be@vcwpuJiro`)d8Z>$(TV@(kYjsjs_Cex7c&oXag%2_HKPoBpQoJ}Y5h%Y|WG*GR1Uk=T@*O|DNb zbHGtQs6vj>GcKp=8R z7bXzGnLTx>3T`pk5)Tu&Oa`uAF; z%^_bZn$5ip)Tv~l2FIYk9rrbEUejUeZA1pFC6N zNiQ7b^W1EFSO>!PjDq;RCwq_Jrtu;z@0u5eqp*7;VFa#~dchlJeIWOp(-V>4{TVHc zh8dZeb;o2p3(!#sh>vuK;%EzfFKrfFXz#A*Zq15rbrL!X8IaZ1zw;?Rj z86eRtm42(EA`49zNEF`vJ=>W1;q6zC<$dmjzVN!4R;tJVzQ5GTTFfyQz=G@Ik$6J9 zkiv<^-jg+Vcg`CX3fF@{D5-}v*F>)ZXaNs)%s1Zq#<>Ew{9bh?-oFah1hOndFV!|{ zc*-Ybxvx{t6}gB8rlp0|!}vdGJ_R9ReOSu$jMN9()!Dqk&gK@+$zB4YuSabfZ0q%e zp2yYu{VaAS%~g*$OUzgo7KaxHRHI@vFi!Kyys5;CkGxnOaPqv^klC=rdEKGS_Qo{% z^!J(TD0kultIUh1c`_zBok~+ynp!(ccq;}eu9DvKD)Uy`kwXo8=4S8_n3n54TEi+{ z$~T53W8Eu@g5#PPy37?(+<0eKada$V))%OO3MAN=`?%T|?Kv)%;?!s4H}QRY^XPr? zI2a7{b>KoUldgEdZq+{UL3IFkGFLeBn1h?;!4E{Nwh&x?>>{QLapA$Pq#U4)56{f1 z-wQ$C25RIhjK0QtGD3{Yc#+6AAACf|2jT)ybcC{Dk>2X2)@NWSuzM%=paPS58r� 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 literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/ext-rspeedtest/files/www/luci-static/resources/img/user.png b/rooter/0optionalapps/ext-rspeedtest/files/www/luci-static/resources/img/user.png new file mode 100644 index 0000000000000000000000000000000000000000..a557423916997d8147307314222fb64bfd32da97 GIT binary patch literal 15663 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 z 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 V3%W2@5)=Rc002ovPDHLkV1jlVc&h*a literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/ext-speedtest/Makefile b/rooter/0optionalapps/ext-speedtest/Makefile new file mode 100644 index 0000000..68a6e47 --- /dev/null +++ b/rooter/0optionalapps/ext-speedtest/Makefile @@ -0,0 +1,34 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-speedtest +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-speedtest + SECTION:=utils + CATEGORY:=ROOter + DEPENDS:=+ext-rspeedtest + SUBMENU:=Optional Applications + TITLE:=support for OpenSpeedTest + PKGARCH:=all +endef + +define Package/ext-speedtest/description + Helper scripts to enable OpenSpeedTest +endef + + +define Build/Compile +endef + +define Package/ext-speedtest/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,ext-speedtest)) diff --git a/rooter/0optionalapps/ext-speedtest/files/usr/lib/lua/luci/controller/speedtest.lua b/rooter/0optionalapps/ext-speedtest/files/usr/lib/lua/luci/controller/speedtest.lua new file mode 100644 index 0000000..2c78f99 --- /dev/null +++ b/rooter/0optionalapps/ext-speedtest/files/usr/lib/lua/luci/controller/speedtest.lua @@ -0,0 +1,11 @@ +module("luci.controller.speedtest", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + entry({"admin", "speed"}, firstchild(), translate("Speed Test"), 95).dependent=false + page = entry({"admin", "speed", "speedtest"}, template("speedtest/speedtest"), translate("OpenSpeedTest"), 71) + page.dependent = true +end diff --git a/rooter/0optionalapps/ext-speedtest/files/usr/lib/lua/luci/view/speedtest/speedtest.htm b/rooter/0optionalapps/ext-speedtest/files/usr/lib/lua/luci/view/speedtest/speedtest.htm new file mode 100644 index 0000000..8f731de --- /dev/null +++ b/rooter/0optionalapps/ext-speedtest/files/usr/lib/lua/luci/view/speedtest/speedtest.htm @@ -0,0 +1,45 @@ +<%+header%> + + + +
                +
                +

                <%:Browser Speed Test%>

                +
                <%:A Speed Test using OpenSpeedTest that runs in the browser%>
                + + + + + + + + + +
                + +
                + + + + + +
                + + + +
                +
                +<%+footer%> diff --git a/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/css/iconmoon_splash.css b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/css/iconmoon_splash.css new file mode 100644 index 0000000..5254b92 --- /dev/null +++ b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/css/iconmoon_splash.css @@ -0,0 +1,69 @@ +@font-face { + font-family: 'icomoon_splash'; + src: url('../fonts/icomoon_splash.eot?vja16g'); + src: url('../fonts/icomoon_splash.eot?vja16g#iefix') format('embedded-opentype'), + url('../fonts/icomoon_splash.ttf?vja16g') format('truetype'), + url('../fonts/icomoon_splash.woff?vja16g') format('woff'), + url('../fonts/icomoon_splash.svg?vja16g#icomoon_splash') format('svg'); + font-weight: normal; + font-style: normal; +} + +[class^="icon-"], [class*=" icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'icomoon_splash' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + + +.icon-power-off:before { + content: "\f011"; +} +.icon-signal:before { + content: "\f012"; +} +.icon-cog:before { + content: "\f013"; +} +.icon-gear:before { + content: "\f013"; +} +.icon-home:before { + content: "\f015"; +} +.icon-exclamation-triangle:before { + content: "\f071"; +} +.icon-warning:before { + content: "\f071"; +} +.icon-comments:before { + content: "\f086"; +} +.icon-hdd-o:before { + content: "\f0a0"; +} +.icon-plug:before { + content: "\f1e6"; +} +.icon-wifi:before { + content: "\f1eb"; +} +.icon-connection:before { + content: "\e91b"; +} +.icon-podcast:before { + content: "\e91c"; +} +.icon-earth:before { + content: "\e9ca"; +} diff --git a/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/css/splash.css b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/css/splash.css new file mode 100644 index 0000000..85af002 --- /dev/null +++ b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/css/splash.css @@ -0,0 +1,341 @@ +/* @override http://src.dev.lo.lo/ROOter/www/luci-static/rooter/css/splash.css */ + +/* + CSS for ROOter splash pages + Copyright Francois Dechery + https://github.com/soif +*/ + +/* @group Splash Pages +--------------------------------------------------*/ + +.rooterSplash{ + padding: 0; + background: #F0F0F0; +} +.rooterPageHead{ + background: #55F; + padding: 10px 5px; + background: rgb(140,140,255); + background: -moz-linear-gradient(top, rgba(140,140,255,1) 0%, rgba(85,85,255,1) 100%); + background: -webkit-linear-gradient(top, rgba(140,140,255,1) 0%,rgba(85,85,255,1) 100%); + background: linear-gradient(to bottom, rgba(140,140,255,1) 0%,rgba(85,85,255,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#8c8cff', endColorstr='#5555ff',GradientType=0 ); + border-bottom: 1px solid rgba(0,0,0,0.7); + +} +.rooterPageContent{ + border-top: 1px solid rgba(255,255,255,0.8); + border-bottom: 1px solid rgba(0,0,0, 0.1); + padding: 25px 10px; + max-width: 1200px; + margin: auto; +} + +.rooterPageContentBut{ + border-top: 1px solid rgba(255,255,255,0.8); + border-bottom: 1px solid rgba(0,0,0, 0.1); + padding: 25px 10px; + max-width: 600px; + margin: auto; +} + +.rooterHeadTitle{ + color: #fff; + text-align: center; + font-family: Georgia, "Times New Roman", Times, serif; + font-size: 32px; + line-height: 120%; + text-shadow: -1px -1px 2px rgba(0,0,0,0.5); +} +.rooterPageFoot{ + border-top: 1px solid rgba(255,255,255,0.8); + margin-top: 20px; + padding: 10px 10px; + max-width: 950px; + margin: auto; + font-size: 16px; +} +.rooterFootMenu{ + float: left; + margin-bottom: 10px; +} +.rooterFootMenu A{ + text-decoration: none; +} +.rooterFootMenu A:hover{ + color: #000; +} +.rooterFootMenu UL{ + padding: 0; + margin: 0; + overflow: hidden; + display: inline-block; +} +.rooterFootMenu LI{ + float: left; + padding: 0; + margin: 0; + list-style: none; +} +.rooterFootMenu LI A{ + padding: 0 10px; + color: #555; +} +.rooterFootMenu LI:first-child A{ + padding-left: 0; +} +.rooterFootCredits{ + float: right; + padding: 0; + margin: 0; + color: #999; + text-align: right; +} +.rooterFootCredits A{ + color: #777; +} +/* @end */ + + + + +/* @group Page: Home +--------------------------------------------------*/ + + +/* @group Logo +++++++++++++++++++ */ +.rooterHeadBox{ + font-size: 50px; + font-family: Georgia, "Times New Roman", Times, serif; + color: #fff; + line-height: 100%; + overflow: hidden; + width: 700px; + margin: auto; + padding-top: 10px; + opacity: 0; +} +.rooterLogo{ + background: url("../img/kangaroo_800.png") no-repeat; + background-size: 100%; + float: left; + height: 110px; + width: 250px; + opacity: 0.4; +} +.rooterTagline{ + margin-left: 100px; + padding-left: 10px; + text-shadow: 2px 2px 3px rgba(0,0,0,0.3); +} + +/* @end */ + +@media only screen and (max-width: 600px) { + .rooterHeadBox{ + text-align: center; + width: auto; + } + .rooterLogo{ + display: inline-block; + float: none; + } + .rooterTagline { + display: none; + } + .rooterFootCredits, + .rooterFootMenu{ + float: none; + text-align: center; + } +} + +#rooterItems{ + clear: both; + max-width: 600px ; + margin: auto; +} + +#rooterItemss{ + clear: both; + max-width: 350px ; + margin: auto; +} +.rooterItem{ + overflow: hidden; + border: 5px solid #00; + border-color: #00 #DDD #DDD #00; + padding: 20px 15px; + margin-bottom: 20px; + border-radius: 8px; + background-color: #AFAFAF; +} +.rooterItem:hover{ + background-color: #CFCFCF; + border-color: #AAA; +} +.rooterItemTitle{ + float: left; + font-size: 18px; + font-weight: bold; + padding-right: 10px; + color: #000; + line-height: 2em; +} +.rooterItemTitle .icon{ + color: #55F; + margin-right: 8px; + font-size: 2em; + vertical-align: middle; +} + +.rooterItemsp{ + overflow: hidden; + border: 5px solid #00; + border-color: #00 #DDD #DDD #00; + padding: 5px 15px; + margin-bottom: 5px; + border-radius: 8px; + background-color: #AFAFAF; +} +.rooterItemsp:hover{ + background-color: #CFCFCF; + border-color: #AAA; +} + +#rooterItems A{ + text-decoration: none; +} +.rooterItemDesc{ + font-size: 18px; + color: #777; + margin-left: 220px; + margin-top: 0.7em; +} +/* @end */ + + + +/* @group Page: Status +--------------------------------------------------*/ + +.modemStatusBlock{ + margin-bottom: 30px; +} +#rooterSplashStatus h3{ + clear:both; + font-size: 18px; + color: #55F; +} +#rooterSplashStatus h3 .icon{ + margin-right: 3px; +} +#rooterSplashStatus h3 .msCell{ + color: #666; +} +.modemStatusRow{ + clear:both; + padding-bottom: 20px; + overflow: hidden; +} +.modemStatusRow .msTitle{ + border-radius: 2px 2px 0 0; + padding: 5px 5px ; + background: #484848; + color: #fff; + background: rgb(99,99,99); + background: -moz-linear-gradient(top, rgba(99,99,99,1) 0%, rgba(72,72,72,1) 100%); + background: -webkit-linear-gradient(top, rgba(99,99,99,1) 0%,rgba(72,72,72,1) 100%); + background: linear-gradient(to bottom, rgba(99,99,99,1) 0%,rgba(72,72,72,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#636363', endColorstr='#484848',GradientType=0 ); +} +.modemStatusRow .msCell{ + border-radius: 10px; + display: inline-block; + margin-top: 10px; + float:left; + border: 1px solid #ccc; + padding-bottom: 5px; + background: #fff; + +} +.modemStatusRow1 .msCell{ + width: 176px; + margin: 10px 5px 0 5px; + text-align: center; +} +.modemStatusRow1 SPAN B{ + font-weight: bold; + font-size: 35px; + line-height: 110%; + text-shadow: 1px 1px 1px rgba(0,0,0,0.4); +} +.modemStatusRow1 .msDesc{ + color: #000; + font-size: 12px; +} +.modemStatusRow2 .msCell{ + margin: 10px 5px; + text-align: center; +} +.modemStatusRow2 SPAN{ + display: inline-block; + padding: 5px 5px ; + font-size: 14px; +} +#counter_div{ + color: #000; + font-weight: normal; + font-size: 14px; +} +#counter_val{ + color: #F00; + font-size: 32px; + font-weight: bold; + text-shadow: 1px 1px 1px rgba(0,0,0,0.1); +} +#msCell_per{} +#msCell_csq{} +#msCell_rssi{} +#msCell_rscp{} +#msCell_ecio{} + +#rooterSplashStatus .level_0{ + color: #0F0; // green +} +#rooterSplashStatus .level_1{ + color: #0CB; // green blue +} +#rooterSplashStatus .level_2{ + color: #00F; // blue +} +#rooterSplashStatus .level_3{ + color: #F0F; // violet +} +#rooterSplashStatus .level_4{ + color: #F80; // orange +} +#rooterSplashStatus .level_5{ + color: #F00; // red +} +#rooterSplashStatus .level_6{ + color: #FF0; // yellow +} + +/* @end */ + + +/* Easy Color changer ------------- */ + +.rooterPageHead{ + /*background: #55F;*/ +} +.rooterItemTitle .icon, +#rooterSplashStatus h3{ + color: #55F; +} + + + diff --git a/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.eot b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.eot new file mode 100644 index 0000000000000000000000000000000000000000..29cd4d1f36a419b4822d210be985dbde03d1d3ac GIT binary patch literal 4708 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 Gn*ReFo8=Jz literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.svg b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.svg new file mode 100644 index 0000000..dc2127b --- /dev/null +++ b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.svg @@ -0,0 +1,22 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.ttf b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4e27645c4f897ba62acace85a644aff591860682 GIT binary patch literal 4516 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 E0b}jXx&QzG literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.woff b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/fonts/icomoon_splash.woff new file mode 100644 index 0000000000000000000000000000000000000000..63f541307f5f723c6eed5ef792b2fbce8e4ea0f7 GIT binary patch literal 4592 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 Vg5RoPjlsG#(%?z@pM}q8{|Cw&)JOmT literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/img/favicon.gif b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/img/favicon.gif new file mode 100644 index 0000000000000000000000000000000000000000..bfbe292825c753540fdd42af7823e167398874e3 GIT binary patch literal 2441 zcmeH|`8yMi1ILGvYixGm<15Ef&K%XGWGY8nBu7{bHJZ6{Bq|yscV0Es=-6N-A(-ME%9Np_=t!2*uVA^pYRf&^oF*( z!kS&-EpG5uH*l{TxRV6!^#p$+f%{32esA!AJ7mBc^4SMD;Dwm+ z27mR1ehY+82SVo_AZCK0^C8fMhtQw*U`zLPrpg^~%uvH4| zR~USY0^6d(w<)k~Dq=SrwjF`kjeze(!gizJ`%%b)NW{S-BsU7a7me79g>z!yoLB@m z8qSS@AH>4BaR_d_>~^fmdYtMGUF{$RKa+-^Prtszyu;22{FEKml}G8$3+pfZFU$YO z{}=)J9UuHTLD06{K*D3&R(~8_?#haa^F?N!o zlsMu-tc*~Fu@K71ve@CNwg^8j>SkxAJ@sOYs-55BSd6OxPnr%@m}yrPk)mpvtnxqj0ew6D_ujjAtxs9Bikc{4)t`0#pbMT~G)cdhPSVxAf6tlIkb>#o#LkpANO z;*El?g2y5AzgOIAzHw*8vYrPu&2+urXN7WtTbHZ$vY6*WO*c1xHrYBD7#QszaOw^d z>-k?yKIn&&oQ(h)c6}6<@_hD1kok~BBm&DXe_Lv#M&9c`gl(6H@=6gdF#^nJ1w$3q zF^f2j*81G|V|}KX5S#M+Z&*1Q;?3Je^O(1f)qK|s!wi010}AN{OwS}+=n3)Nx%9mj zCD!EF!keOq9hyk7_l_Yxfrjs7q@ANLWIrvxrrz?4nF=Hb1PTZ#U53oQz)4~-1p@N; zl-%RmD#L{+P3~F-*dPZ_E5=pqCNeErR6IPYv&hQNy~w*#g~dC19;I!M+<*AU-NT-L z*(IE@SkUvhVIhdg`&_NOn}GX~+1vMJnJ~$Mzbpk#7c*F|l^AccH-v>Fqy-9apI?1& zD_*V`Gd@DhSLNKsNbi{MmAsmsh%Ie$_l}!rKqS#FzzM{cYwrlhd;vUy$b28${n!kz zcEA-GxR4@dZB&eplBroUgQrx%@n-`Q9Bew!&-S0UuNuCs>?&B_p0{s(0hOWAe)8jP-l7 zm9g(i8~0aBK~87;bLP}PPGEnJ?@yK#v$U6*MXv164IM7y7>pgA4H@d06Xo>GST&{o zp7-HwZzdi0(OV?q?EA#D_17J*JgnbKU&(skIL{sIrR=ng9t?dkpubtZpE7DSEQosZ z%jV|;!6HXnZ}h8Lds^@+pA)McjrsQ&sD~KNytq2d&PiG*aAS&t2?9f|MMiY!On=l! zYZcWXQz47l9CmmUSlTCoP0jpezTLFV;~g5_H7(KD*DiZ*E$ZsbBrGbrwclRrft>>r zAwS=~VdxvOe4%r%`$g;BijSUHVjgl_&{+2xE#Bs3-rx$m^S7uIr(ODA>bOQRd!76+^)JBhkVD(k)@2uP$fz8W(i z=w7z%1g8o!W>-kVjc05963awysKuSabrsQ1jkO=qnyl|42lg_Wtlc!97MYNKT}=x;&gqW3TbnA}QSS95oj9!b!RS?JE&sX zfbY3Z56Hsl7oD^se@eN*D7{-YPSQFF9%R>M7)=@9+TG+iloJO0ao-8aJR%1;^ACjV#SQ=f literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/img/kangaroo_800.png b/rooter/0optionalapps/ext-speedtest/files/www/luci-static/speed/img/kangaroo_800.png new file mode 100644 index 0000000000000000000000000000000000000000..478fa6d62f4ce758358142fefd480c564773ce36 GIT binary patch literal 5836 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 Wk|dU(LN#0f0000/dev/null 2>&1` +then + return +fi +echo "0" > /tmp/texting +uci set modem.general.smsnum='1' +uci commit modem \ No newline at end of file diff --git a/rooter/0optionalapps/ext-texting/files/usr/lib/fullmenu/dotext.sh b/rooter/0optionalapps/ext-texting/files/usr/lib/fullmenu/dotext.sh new file mode 100644 index 0000000..5767c1f --- /dev/null +++ b/rooter/0optionalapps/ext-texting/files/usr/lib/fullmenu/dotext.sh @@ -0,0 +1,123 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "TEXTING" "$@" +} + +handle_numbers() { + let "NUMBERS = $NUMBERS + 1" + if [ $NUMBERS -eq $nindex ]; then + numch=$1 + fi +} + +do_numbers() { + local config=$1 + config_list_foreach "$config" number handle_numbers +} + +handle_messages() { + let "NUMBERS = $NUMBERS + 1" + if [ $NUMBERS -eq $nindex ]; then + numch=$1 + fi +} + +do_messages() { + local config=$1 + config_list_foreach "$config" message handle_messages +} + +sendmsg() { + nnum=$(uci -q get texting.texting.numbers) + mnum=$(uci -q get texting.texting.messages) + delay=$(uci -q get texting.texting.interval) + NUMBERS=0 + RANDOM=$(date +%s%N | cut -b10-19) + RAN=$RANDOM + RAN1=${RAN:0:1} + if [ $RAN1 = "0" ]; then + RAN="1"$RAN + rlen=${#RAN} + if [ $rlen -gt 9 ]; then + RAN=${RAN:0:8} + fi + fi + nindex=$(( $RAN % $nnum + 1 )) + config_load texting + config_foreach do_numbers numbers + Phone=$numch + NUMBERS=0 + RANDOM=$(date +%s%N | cut -b10-19) + RAN=$RANDOM + RAN1=${RAN:0:1} + if [ $RAN1 = "0" ]; then + RAN="1"$RAN + rlen=${#RAN} + if [ $rlen -gt 9 ]; then + RAN=${RAN:0:8} + fi + fi + nindex=$(( $RAN % $mnum + 1 )) + config_foreach do_messages messages + Message=$numch + /usr/lib/fullmenu/chksms.sh + if [ -e /tmp/texting ]; then + /usr/lib/sms/smsout.sh "$Phone" "$Message" + fi +} + +checktime() { + shour=$(uci -q get texting.texting.starthour) + smin=$(uci -q get texting.texting.startmin) + ehour=$(uci -q get texting.texting.endhour) + emin=$(uci -q get texting.texting.endmin) + chour=$(date +%H) + cmin=$(date +%M) + if [ $shour -gt $chour ]; then + flag="0" + else + if [ $shour -eq $chour ]; then + if [ $smin -le $cmin ]; then + flag="1" + else + flag="0" + fi + else + flag="1" + fi + fi + + if [ $flag = "1" ]; then + if [ $ehour -lt $chour ]; then + flag="0" + else + if [ $ehour -eq $chour ]; then + if [ $emin -lt $cmin ]; then + flag="0" + else + flag="1" + fi + else + flag="1" + fi + fi + fi + + echo $flag +} + +while true +do + running=$(checktime) + if [ $running = "1" ]; then + EN=$(uci -q get texting.setting.enabled) + if [ $EN = "1" ]; then + sendmsg + sleep $delay + fi + else + sleep 900 + fi +done \ No newline at end of file diff --git a/rooter/0optionalapps/ext-texting/files/usr/lib/fullmenu/text-setup.sh b/rooter/0optionalapps/ext-texting/files/usr/lib/fullmenu/text-setup.sh new file mode 100644 index 0000000..5d57226 --- /dev/null +++ b/rooter/0optionalapps/ext-texting/files/usr/lib/fullmenu/text-setup.sh @@ -0,0 +1,63 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "TEXTING" "$@" +} + +sleep 3 + +handle_numbers() { + let "NUMBERS = $NUMBERS + 1" +} + +do_numbers() { + local config=$1 + config_list_foreach "$config" number handle_numbers +} + +handle_messages() { + let "NUMBERS = $NUMBERS + 1" +} + +do_messages() { + local config=$1 + config_list_foreach "$config" message handle_numbers +} + +SHOUR=$(uci -q get texting.setting.start) +HOUR=`expr $SHOUR / 4` +let "TH = $HOUR * 4" +let "TMP1 = $SHOUR - $TH" +let "MIN = $TMP1 * 15" +uci set texting.texting.starthour=$HOUR +uci set texting.texting.startmin=$MIN +EHOUR=$(uci -q get texting.setting.end) +HOUR=`expr $EHOUR / 4` +let "TH = $HOUR * 4" +let "TMP1 = $EHOUR - $TH" +let "MIN = $TMP1 * 15" +uci set texting.texting.endhour=$HOUR +uci set texting.texting.endmin=$MIN + +NUMBERS=0 +config_load texting +config_foreach do_numbers numbers +uci set texting.texting.numbers=$NUMBERS +NUMBERS=0 +config_foreach do_messages messages +uci set texting.texting.messages=$NUMBERS + +TIMES=$(uci -q get texting.setting.times) +let "TH = $EHOUR - $SHOUR" +let "TMIN = $TH * 15" +let "INTERVAL = $TMIN / $TIMES" +let "INTERVAL = $INTERVAL * 60" +uci set texting.texting.interval=$INTERVAL +uci commit texting + +result=`ps | grep -i "dotext.sh" | grep -v "grep" | wc -l` +if [ $result -lt 1 ]; then + /usr/lib/fullmenu/dotext.sh & +fi + diff --git a/rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/controller/texting.lua b/rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/controller/texting.lua new file mode 100644 index 0000000..a729365 --- /dev/null +++ b/rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/controller/texting.lua @@ -0,0 +1,32 @@ +module("luci.controller.texting", package.seeall) +function index() + local lock = luci.model.uci.cursor():get("custom", "menu", "full") + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + if lock == "1" then + if (multilock == "1" and rootlock == "1") then + entry({"admin", "adminmenu", "texting"}, cbi("fullmenu/texting"), "Random Texting", 9) + else + entry({"admin", "adminmenu", "texting"}, cbi("fullmenu/texting"), "---Random Texting", 9) + end + end + end + + entry({"admin", "services", "chksms"}, call("action_chksms")) +end + +function action_chksms() + local rv = {} + os.execute("/usr/lib/fullmenu/chksms.sh") + file = io.open("/tmp/texting", "r") + if file ~= nil then + rv["sms"] = "1" + file:close() + else + rv["sms"] = "0" + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end \ No newline at end of file diff --git a/rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/model/cbi/fullmenu/texting.lua b/rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/model/cbi/fullmenu/texting.lua new file mode 100644 index 0000000..d689c0b --- /dev/null +++ b/rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/model/cbi/fullmenu/texting.lua @@ -0,0 +1,254 @@ +local utl = require "luci.util" + +m = Map("texting", translate("Random Texting"), translate("Send random message to number at random times")) + +m.on_after_save = function(self) + luci.sys.call("/usr/lib/fullmenu/text-setup.sh &") +end + +s = m:section(TypedSection, "setting", "Global Settings") +s.anonymous = true +s.addremove = false + +s:option(Flag, "enabled", translate("Enabled : ")) + +sdhour = s:option(ListValue, "start", translate("Starting Time :")) +sdhour.rmempty = true +sdhour:value("0", "12:00 AM") +sdhour:value("1", "12:15 AM") +sdhour:value("2", "12:30 AM") +sdhour:value("3", "12:45 AM") +sdhour:value("4", "01:00 AM") +sdhour:value("5", "01:15 AM") +sdhour:value("6", "01:30 AM") +sdhour:value("7", "01:45 AM") +sdhour:value("8", "02:00 AM") +sdhour:value("9", "02:15 AM") +sdhour:value("10", "02:30 AM") +sdhour:value("11", "02:45 AM") +sdhour:value("12", "03:00 AM") +sdhour:value("13", "03:15 AM") +sdhour:value("14", "03:30 AM") +sdhour:value("15", "03:45 AM") +sdhour:value("16", "04:00 AM") +sdhour:value("17", "04:15 AM") +sdhour:value("18", "04:30 AM") +sdhour:value("19", "04:45 AM") +sdhour:value("20", "05:00 AM") +sdhour:value("21", "05:15 AM") +sdhour:value("22", "05:30 AM") +sdhour:value("23", "05:45 AM") +sdhour:value("24", "06:00 AM") +sdhour:value("25", "06:15 AM") +sdhour:value("26", "06:30 AM") +sdhour:value("27", "06:45 AM") +sdhour:value("28", "07:00 AM") +sdhour:value("29", "07:15 AM") +sdhour:value("30", "07:30 AM") +sdhour:value("31", "07:45 AM") +sdhour:value("32", "08:00 AM") +sdhour:value("33", "08:15 AM") +sdhour:value("34", "08:30 AM") +sdhour:value("35", "08:45 AM") +sdhour:value("36", "09:00 AM") +sdhour:value("37", "09:15 AM") +sdhour:value("38", "09:30 AM") +sdhour:value("39", "09:45 AM") +sdhour:value("40", "10:00 AM") +sdhour:value("41", "10:15 AM") +sdhour:value("42", "10:30 AM") +sdhour:value("43", "10:45 AM") +sdhour:value("44", "11:00 AM") +sdhour:value("45", "11:15 AM") +sdhour:value("46", "11:30 AM") +sdhour:value("47", "11:45 AM") +sdhour:value("48", "12:00 PM") +sdhour:value("49", "12:15 PM") +sdhour:value("50", "12:30 PM") +sdhour:value("51", "12:45 PM") +sdhour:value("52", "01:00 PM") +sdhour:value("53", "01:15 PM") +sdhour:value("54", "01:30 PM") +sdhour:value("55", "01:45 PM") +sdhour:value("56", "02:00 PM") +sdhour:value("57", "02:15 PM") +sdhour:value("58", "02:30 PM") +sdhour:value("59", "02:45 PM") +sdhour:value("60", "03:00 PM") +sdhour:value("61", "03:15 PM") +sdhour:value("62", "03:30 PM") +sdhour:value("63", "03:45 PM") +sdhour:value("64", "04:00 PM") +sdhour:value("65", "04:15 PM") +sdhour:value("66", "04:30 PM") +sdhour:value("67", "04:45 PM") +sdhour:value("68", "05:00 PM") +sdhour:value("69", "05:15 PM") +sdhour:value("70", "05:30 PM") +sdhour:value("71", "05:45 PM") +sdhour:value("72", "06:00 PM") +sdhour:value("73", "06:15 PM") +sdhour:value("74", "06:30 PM") +sdhour:value("75", "06:45 PM") +sdhour:value("76", "07:00 PM") +sdhour:value("77", "07:15 PM") +sdhour:value("78", "07:30 PM") +sdhour:value("79", "07:45 PM") +sdhour:value("80", "08:00 PM") +sdhour:value("81", "08:15 PM") +sdhour:value("82", "08:30 PM") +sdhour:value("83", "08:45 PM") +sdhour:value("84", "09:00 PM") +sdhour:value("85", "09:15 PM") +sdhour:value("86", "09:30 PM") +sdhour:value("87", "09:45 PM") +sdhour:value("88", "10:00 PM") +sdhour:value("89", "10:15 PM") +sdhour:value("90", "10:30 PM") +sdhour:value("91", "10:45 PM") +sdhour:value("92", "11:00 PM") +sdhour:value("93", "11:15 PM") +sdhour:value("94", "11:30 PM") +sdhour:value("95", "11:45 PM") +sdhour.default = "32" + +sdhour = s:option(ListValue, "end", translate("Ending Time :")) +sdhour.rmempty = true +sdhour:value("0", "12:00 AM") +sdhour:value("1", "12:15 AM") +sdhour:value("2", "12:30 AM") +sdhour:value("3", "12:45 AM") +sdhour:value("4", "01:00 AM") +sdhour:value("5", "01:15 AM") +sdhour:value("6", "01:30 AM") +sdhour:value("7", "01:45 AM") +sdhour:value("8", "02:00 AM") +sdhour:value("9", "02:15 AM") +sdhour:value("10", "02:30 AM") +sdhour:value("11", "02:45 AM") +sdhour:value("12", "03:00 AM") +sdhour:value("13", "03:15 AM") +sdhour:value("14", "03:30 AM") +sdhour:value("15", "03:45 AM") +sdhour:value("16", "04:00 AM") +sdhour:value("17", "04:15 AM") +sdhour:value("18", "04:30 AM") +sdhour:value("19", "04:45 AM") +sdhour:value("20", "05:00 AM") +sdhour:value("21", "05:15 AM") +sdhour:value("22", "05:30 AM") +sdhour:value("23", "05:45 AM") +sdhour:value("24", "06:00 AM") +sdhour:value("25", "06:15 AM") +sdhour:value("26", "06:30 AM") +sdhour:value("27", "06:45 AM") +sdhour:value("28", "07:00 AM") +sdhour:value("29", "07:15 AM") +sdhour:value("30", "07:30 AM") +sdhour:value("31", "07:45 AM") +sdhour:value("32", "08:00 AM") +sdhour:value("33", "08:15 AM") +sdhour:value("34", "08:30 AM") +sdhour:value("35", "08:45 AM") +sdhour:value("36", "09:00 AM") +sdhour:value("37", "09:15 AM") +sdhour:value("38", "09:30 AM") +sdhour:value("39", "09:45 AM") +sdhour:value("40", "10:00 AM") +sdhour:value("41", "10:15 AM") +sdhour:value("42", "10:30 AM") +sdhour:value("43", "10:45 AM") +sdhour:value("44", "11:00 AM") +sdhour:value("45", "11:15 AM") +sdhour:value("46", "11:30 AM") +sdhour:value("47", "11:45 AM") +sdhour:value("48", "12:00 PM") +sdhour:value("49", "12:15 PM") +sdhour:value("50", "12:30 PM") +sdhour:value("51", "12:45 PM") +sdhour:value("52", "01:00 PM") +sdhour:value("53", "01:15 PM") +sdhour:value("54", "01:30 PM") +sdhour:value("55", "01:45 PM") +sdhour:value("56", "02:00 PM") +sdhour:value("57", "02:15 PM") +sdhour:value("58", "02:30 PM") +sdhour:value("59", "02:45 PM") +sdhour:value("60", "03:00 PM") +sdhour:value("61", "03:15 PM") +sdhour:value("62", "03:30 PM") +sdhour:value("63", "03:45 PM") +sdhour:value("64", "04:00 PM") +sdhour:value("65", "04:15 PM") +sdhour:value("66", "04:30 PM") +sdhour:value("67", "04:45 PM") +sdhour:value("68", "05:00 PM") +sdhour:value("69", "05:15 PM") +sdhour:value("70", "05:30 PM") +sdhour:value("71", "05:45 PM") +sdhour:value("72", "06:00 PM") +sdhour:value("73", "06:15 PM") +sdhour:value("74", "06:30 PM") +sdhour:value("75", "06:45 PM") +sdhour:value("76", "07:00 PM") +sdhour:value("77", "07:15 PM") +sdhour:value("78", "07:30 PM") +sdhour:value("79", "07:45 PM") +sdhour:value("80", "08:00 PM") +sdhour:value("81", "08:15 PM") +sdhour:value("82", "08:30 PM") +sdhour:value("83", "08:45 PM") +sdhour:value("84", "09:00 PM") +sdhour:value("85", "09:15 PM") +sdhour:value("86", "09:30 PM") +sdhour:value("87", "09:45 PM") +sdhour:value("88", "10:00 PM") +sdhour:value("89", "10:15 PM") +sdhour:value("90", "10:30 PM") +sdhour:value("91", "10:45 PM") +sdhour:value("92", "11:00 PM") +sdhour:value("93", "11:15 PM") +sdhour:value("94", "11:30 PM") +sdhour:value("95", "11:45 PM") +sdhour.default = "68" + +sdhour = s:option(ListValue, "times", translate("Times per Day :")) +sdhour.rmempty = true +sdhour:value("2", "2") +sdhour:value("4", "4") +sdhour:value("6", "6") +sdhour:value("8", "8") +sdhour:value("10", "10") +sdhour:value("12", "12") +sdhour:value("14", "14") +sdhour:value("16", "16") +sdhour:value("18", "18") +sdhour:value("20", "20") +sdhour:value("22", "22") +sdhour:value("24", "24") +sdhour:value("26", "26") +sdhour:value("28", "28") +sdhour:value("30", "30") +sdhour:value("32", "32") +sdhour:value("34", "34") +sdhour:value("36", "36") +sdhour:value("38", "38") +sdhour:value("40", "40") +sdhour.default = "10" + + +s = m:section(TypedSection, "numbers", "Phone Numbers") +s.anonymous = true +s.addremove = false + +o = s:option(DynamicList, "number", translate("List of Phone Numbers : ")) + +s = m:section(TypedSection, "messages", "Messages") +s.anonymous = true +s.addremove = false + +o = s:option(DynamicList, "message", translate("List of Messages : ")) + +m:section(SimpleSection).template = "fullmenu/textarea" + +return m \ No newline at end of file diff --git a/rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/view/fullmenu/textarea.htm b/rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/view/fullmenu/textarea.htm new file mode 100644 index 0000000..fd7c69f --- /dev/null +++ b/rooter/0optionalapps/ext-texting/files/usr/lib/lua/luci/view/fullmenu/textarea.htm @@ -0,0 +1,103 @@ +<% + load_icon = resource .. "/icons/loading.gif" +%> + + + + +
                + <%:Manual Texting%> + + + + + + + + + +
                Phone Number :
                Message :
                 
                + + + + + + + + + +
                diff --git a/rooter/0optionalapps/ext-throttle/Makefile b/rooter/0optionalapps/ext-throttle/Makefile new file mode 100644 index 0000000..cf731cc --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-throttle +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-throttle + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + DEPENDS:=+tc +kmod-sched-core +kmod-ifb +iptables \ + +iptables-mod-ipopt +iptables-mod-conntrack-extra \ + +kmod-sched-cake + TITLE:=support for Throttle + PKGARCH:=all +endef + +define Package/ext-throttle/description + Helper scripts to enable Throttle +endef + + +define Build/Compile +endef + +define Package/ext-throttle/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,ext-throttle)) diff --git a/rooter/0optionalapps/ext-throttle/files/etc/config/sqm b/rooter/0optionalapps/ext-throttle/files/etc/config/sqm new file mode 100644 index 0000000..67f58de --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/etc/config/sqm @@ -0,0 +1,34 @@ + +config queue 'wan' + option enabled '0' + option download '85000' + option upload '10000' + option qdisc 'cake' + option script 'piece_of_cake.qos' + option linklayer 'none' + option interface '0' + option debug_logging '0' + option verbosity '5' + +config queue 'wan1' + option enabled '0' + option download '85000' + option upload '10000' + option qdisc 'cake' + option script 'piece_of_cake.qos' + option linklayer 'none' + option debug_logging '0' + option verbosity '5' + option interface '0' + +config queue 'wan2' + option enabled '0' + option download '85000' + option upload '10000' + option qdisc 'cake' + option script 'piece_of_cake.qos' + option linklayer 'none' + option interface '0' + option debug_logging '0' + option verbosity '5' + diff --git a/rooter/0optionalapps/ext-throttle/files/etc/hotplug.d/iface/11-sqm b/rooter/0optionalapps/ext-throttle/files/etc/hotplug.d/iface/11-sqm new file mode 100644 index 0000000..75ff4ea --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/etc/hotplug.d/iface/11-sqm @@ -0,0 +1,27 @@ +#!/bin/sh + +if [ "$ACTION" = ifdown ]; then + if [ $INTERFACE = "wan" -o $INTERFACE = "wan1" -o $INTERFACE = "wan2" ]; then + uci set sqm.$INTERFACE.interface='0' + uci commit sqm + logger -t THROTTLE-DEBUG "$ACTION $INTERFACE" + fi +fi + +[ -n "$DEVICE" ] || exit 0 + +restart_sqm() { + /usr/lib/sqm/run.sh stop ${DEVICE} + /usr/lib/sqm/run.sh start ${DEVICE} +} + +if [ "$ACTION" = ifup ]; then + if [ $INTERFACE = "wan" -o $INTERFACE = "wan1" -o $INTERFACE = "wan2" ]; then + uci set sqm.$INTERFACE.interface=$DEVICE + uci commit sqm + /etc/init.d/sqm enabled + restart_sqm + logger -t THROTTLE-DEBUG "$DEVICE $ACTION $INTERFACE" + fi +fi + diff --git a/rooter/0optionalapps/ext-throttle/files/etc/init.d/sqm b/rooter/0optionalapps/ext-throttle/files/etc/init.d/sqm new file mode 100644 index 0000000..3badb62 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/etc/init.d/sqm @@ -0,0 +1,31 @@ +#!/bin/sh /etc/rc.common + +START=50 +USE_PROCD=1 + +service_triggers() +{ + procd_add_reload_trigger "sqm" +} + +reload_service() +{ + stop "$@" + start "$@" +} + +start_service() +{ + /usr/lib/sqm/run.sh start "$@" +} + +stop_service() +{ + /usr/lib/sqm/run.sh stop "$@" +} + +boot() +{ + export SQM_VERBOSITY_MIN=5 # Silence errors + start "$@" +} diff --git a/rooter/0optionalapps/ext-throttle/files/etc/sqm/sqm.conf b/rooter/0optionalapps/ext-throttle/files/etc/sqm/sqm.conf new file mode 100644 index 0000000..b9a98b4 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/etc/sqm/sqm.conf @@ -0,0 +1,5 @@ +SQM_LIB_DIR=/usr/lib/sqm +SQM_STATE_DIR=/var/run/sqm +SQM_QDISC_STATE_DIR=${SQM_STATE_DIR}/available_qdiscs +SQM_CHECK_QDISCS="fq_codel codel pie sfq cake" +SQM_SYSLOG=1 diff --git a/rooter/0optionalapps/ext-throttle/files/etc/uci-defaults/50-luci-sqm b/rooter/0optionalapps/ext-throttle/files/etc/uci-defaults/50-luci-sqm new file mode 100644 index 0000000..b3aa47c --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/etc/uci-defaults/50-luci-sqm @@ -0,0 +1,12 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@sqm[-1] + add ucitrack sqm + set ucitrack.@sqm[-1].init=sqm + del_list ucitrack.@firewall[0].affects=sqm + add_list ucitrack.@firewall[0].affects=sqm + commit ucitrack +EOF + +exit 0 diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/defaults.sh b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/defaults.sh new file mode 100644 index 0000000..009cfc6 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/defaults.sh @@ -0,0 +1,109 @@ +# You need to jiggle these parameters. Note limits are tuned towards a <10Mbit uplink <60Mbup down + +[ -z "$SCRIPT" ] && SCRIPT= +[ -z "$UPLINK" ] && UPLINK=2302 +[ -z "$DOWNLINK" ] && DOWNLINK=14698 +[ -z "$IFACE" ] && IFACE=eth0 +[ -z "$QDISC" ] && QDISC=fq_codel +[ -z "$LLAM" ] && LLAM="default" +[ -z "$LINKLAYER" ] && LINKLAYER="none" +[ -z "$OVERHEAD" ] && OVERHEAD=0 +[ -z "$STAB_MTU" ] && STAB_MTU=2047 +[ -z "$STAB_MPU" ] && STAB_MPU=0 +[ -z "$STAB_TSIZE" ] && STAB_TSIZE=512 +[ -z "$AUTOFLOW" ] && AUTOFLOW=0 +[ -z "$LIMIT" ] && LIMIT=1001 # sane global default for *LIMIT for fq_codel on a small memory device +[ -z "$ILIMIT" ] && ILIMIT= +[ -z "$ELIMIT" ] && ELIMIT= +[ -z "$ITARGET" ] && ITARGET= +[ -z "$ETARGET" ] && ETARGET= +[ -z "$IECN" ] && IECN="ECN" +[ -z "$EECN" ] && EECN="ECN" +# These two used to be called something else; preserve backwards compatibility +[ -z "$ZERO_DSCP_INGRESS" ] && ZERO_DSCP_INGRESS="${ZERO_DSCP:-${SQUASH_DSCP:-1}}" +[ -z "$IGNORE_DSCP_INGRESS" ] && IGNORE_DSCP_INGRESS="${IGNORE_DSCP:-${SQUASH_INGRESS:-1}}" + +[ -z "$IQDISC_OPTS" ] && IQDISC_OPTS="" +[ -z "$EQDISC_OPTS" ] && EQDISC_OPTS="" + +# handling of specific important binaries +[ -z "$TC" ] && TC=tc_wrapper +[ -z "$TC_BINARY" ] && TC_BINARY=$(command -v tc) +[ -z "$IP" ] && IP=ip_wrapper +[ -z "$IP_BINARY" ] && IP_BINARY=$(command -v ip) +[ -z "$IPTABLES" ] && IPTABLES=iptables_wrapper +[ -z "$IPTABLES_BINARY" ] && IPTABLES_BINARY=$(command -v iptables) +[ -z "$IP6TABLES" ] && IP6TABLES=ip6tables_wrapper +[ -z "$IP6TABLES_BINARY" ] && IP6TABLES_BINARY=$(command -v ip6tables) +[ -z "$IPTABLES_ARGS" ] && IPTABLES_ARGS="-w 1" + + +# Try modprobe first, fall back to insmod +if [ -z "$INSMOD" ]; then + INSMOD=$(command -v modprobe) + if [ -n "$INSMOD" ]; then + INSMOD="${INSMOD} -q" + else + INSMOD=$(command -v insmod) + fi +fi + +[ -z "$TARGET" ] && TARGET="5ms" +[ -z "$IPT_MASK" ] && IPT_MASK="0xff" # to disable: set mask to 0xffffffff +#sm: we need the functions above before trying to set the ingress IFB device +#sm: *_CAKE_OPTS should contain the diffserv keyword for cake +[ -z "$INGRESS_CAKE_OPTS" ] && INGRESS_CAKE_OPTS="diffserv3" +[ -z "$EGRESS_CAKE_OPTS" ] && EGRESS_CAKE_OPTS="diffserv3" + +[ -z "$CUR_DIRECTION" ] && CUR_DIRECTION="NONE" + + +# HTB without a sufficiently large burst/cburst value is a bit CPU hungry +# so allow to specify the permitted burst in the time domain (microseconds) +# so the user has a feeling for the associated worst case latency cost +# set to zero to use htb default butst of one MTU +[ -z "$SHAPER_BURST_DUR_US" ] && SHAPER_BURST_DUR_US=1000 +[ -z "$ISHAPER_BURST_DUR_US" ] && ISHAPER_BURST_DUR_US=$SHAPER_BURST_DUR_US +[ -z "$ESHAPER_BURST_DUR_US" ] && ESHAPER_BURST_DUR_US=$SHAPER_BURST_DUR_US + +# use the same logic for the calculation of htb's quantum +# quantum controlls how many bytes htb tries to deque from the current tier +# before switching tiers. +[ -z "$SHAPER_QUANTUM_DUR_US" ] && SHAPER_QUANTUM_DUR_US=$SHAPER_BURST_DUR_US +[ -z "$ISHAPER_QUANTUM_DUR_US" ] && ISHAPER_QUANTUM_DUR_US=$SHAPER_QUANTUM_DUR_US +[ -z "$ESHAPER_QUANTUM_DUR_US" ] && ESHAPER_QUANTUM_DUR_US=$SHAPER_QUANTUM_DUR_US + + +# Logging verbosity +VERBOSITY_SILENT=0 +VERBOSITY_ERROR=1 +VERBOSITY_WARNING=2 +VERBOSITY_INFO=5 +VERBOSITY_DEBUG=8 +VERBOSITY_TRACE=10 +[ -z "$SQM_VERBOSITY_MAX" ] && SQM_VERBOSITY_MAX=$VERBOSITY_INFO +# For silencing only errors +[ -z "$SQM_VERBOSITY_MIN" ] && SQM_VERBOSITY_MIN=$VERBOSITY_SILENT + +[ -z "$SQM_DEBUG" ] && SQM_DEBUG=0 +if [ "$SQM_DEBUG" -eq "1" ] +then + SQM_DEBUG_STEM="${SQM_STATE_DIR}/${IFACE}" + SQM_START_LOG="${SQM_DEBUG_STEM}.start-sqm.log" + SQM_STOP_LOG="${SQM_DEBUG_STEM}.stop-sqm.log" + [ -z "SQM_DEBUG_LOG" ] && SQM_DEBUG_LOG="${SQM_DEBUG_STEM}.debug.log" + OUTPUT_TARGET="${SQM_DEBUG_LOG}" +else + OUTPUT_TARGET="/dev/null" +fi + + +# Can be overridden by callers that want to silence error output for a +# particular command +SILENT=0 + +# Transaction log for unwinding ipt rules +IPT_TRANS_LOG="${SQM_STATE_DIR}/${IFACE}.iptables.log" + +# These are the modules that do_modules() will attempt to load +ALL_MODULES="act_ipt sch_$QDISC sch_ingress act_mirred cls_fw cls_flow cls_u32 sch_htb sch_hfsc" diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/functions.sh b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/functions.sh new file mode 100644 index 0000000..c61edfa --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/functions.sh @@ -0,0 +1,923 @@ +################################################################################ +# (sqm) functions.sh +# +# These are all helper functions for various parts of SQM scripts. If you want +# to play around with your own shaper-qdisc-filter configuration look here for +# ready made tools, or examples start of on your own. +# +# Please note the SQM logger function is broken down into levels of logging. +# Use only levels appropriate to touch points in your script and realize the +# potential to overflow SYSLOG. +# +################################################################################ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Copyright (C) 2012-2019 +# Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller +# Eric Luehrsen +# +################################################################################ + +# Logging verbosity +VERBOSITY_SILENT=0 +VERBOSITY_ERROR=1 +VERBOSITY_WARNING=2 +VERBOSITY_INFO=5 +VERBOSITY_DEBUG=8 +VERBOSITY_TRACE=10 + +sqm_logger() { + local level_min + local level_max + local debug + + case $1 in + ''|*[!0-9]*) LEVEL=$VERBOSITY_INFO ;; # empty or non-numbers + *) LEVEL=$1; shift ;; + esac + + level_min=${SQM_VERBOSITY_MIN:-$VERBOSITY_SILENT} + level_max=${SQM_VERBOSITY_MAX:-$VERBOSITY_INFO} + debug=${SQM_DEBUG:-0} + + if [ "$level_max" -ge "$LEVEL" ] && [ "$level_min" -le "$LEVEL" ] ; then + if [ "$SQM_SYSLOG" -eq "1" ]; then + logger -t SQM -s "$*" + else + echo "$@" >&2 + fi + fi + + # this writes into SQM_START_LOG or SQM_STOP_LOG, log files are trucated in + # start-sqm/stop-sqm respectively and should only take little space + if [ "$debug" -eq "1" ]; then + echo "$@" >> "${SQM_DEBUG_LOG}" + fi +} + +sqm_error() { sqm_logger $VERBOSITY_ERROR ERROR: "$@"; } +sqm_warn() { sqm_logger $VERBOSITY_WARNING WARNING: "$@"; } +sqm_log() { sqm_logger $VERBOSITY_INFO "$@"; } +sqm_debug() { sqm_logger $VERBOSITY_DEBUG "$@"; } +sqm_trace() { sqm_logger $VERBOSITY_TRACE "$@"; } + + +# Inspired from https://stackoverflow.com/questions/85880/determine-if-a-function-exists-in-bash +#fn_exists() { LC_ALL=C type $1 | grep -q 'is a function'; } +fn_exists() { + local FN_CANDIDATE + local CUR_LC_ALL + local TYPE_OUTPUT + local RET + FN_CANDIDATE=$1 + # check that a candidate nme was given + if [ -z "${FN_CANDIDATE}" ]; then + sqm_error "fn_exists: no function name specified as first argument." + return 1 + fi + sqm_debug "fn_exists: function candidate name: ${FN_CANDIDATE}" + + # extract the textual type description + TYPE_OUTPUT=$( LC_ALL=C type $1 2>&1 ) + sqm_debug "fn_exists: TYPE_OUTPUT: $TYPE_OUTPUT" + + # OpenWrt (2019) returns 'is a function' + # Debian Buster/raspbian returns 'is a shell function' + # let's just hope no Linux system reurn 'is a shell builtin function' + echo ${TYPE_OUTPUT} | grep -q 'is .*function' + RET=$? + + sqm_debug "fn_exists: return value: ${RET}" + return ${RET} +} + + +# Transaction logging for ipt rules to allow for gracefull final teardown +ipt_log_restart() { + [ -f "$IPT_TRANS_LOG" ] && rm -f "$IPT_TRANS_LOG" +} + + +# Function to negate iptables commands. Turns addition and insertion into +# deletion, and creation of new chains into deletion +# Its output has quotes around all parameters so we can preserve arguments +# containing whitespace across log file write & re-read +ipt_negate() +{ + for var in "$@"; do + case "$var" in + "-A"|"-I") echo -n '"-D" ' ;; + "-N") echo -n '"-X" ' ;; + *) echo -n "\"$var\" " ;; + esac + done + echo "" +} + +ipt_log() +{ + echo "$@" >> $IPT_TRANS_LOG +} + +# Split a string containing an iptables command line parameter invocation, then +# run it through ipt(). This is used to turn lines read from the log file, or +# output from ipt_negate() back into proper parameters contained in $@ +ipt_run_split() +{ + eval "set -- $1" + ipt "$@" +} + +# Read the transaction log in reverse and execute using ipt to undo changes. +# Since we logged only ipt '-D' commands, ipt won't add them again to the +# transaction log, but will include them in the syslog/debug log. +ipt_log_rewind() { + [ -f "$IPT_TRANS_LOG" ] || return 0 + sed -n '1!G;h;$p' "$IPT_TRANS_LOG" | + while read line; do + [ -n "$line" ] || continue + ipt_run_split "$line" + done +} + +ipt() { + local neg + + for var in "$@"; do + case "$var" in + "-A"|"-I"|"-N") + # If the rule is an addition rule, we first run its negation, + # then log that negation to be used by ipt_log_rewind() on + # shutdown + neg="$(ipt_negate "$@")" + ipt_run_split "$neg" + ipt_log "$neg" + ;; + esac + done + + SILENT=1 ${IPTABLES} $IPTABLES_ARGS "$@" + SILENT=1 ${IP6TABLES} $IPTABLES_ARGS "$@" +} + + +# wrapper to call iptables to allow debug logging +iptables_wrapper(){ + cmd_wrapper iptables ${IPTABLES_BINARY} "$@" +} + +# wrapper to call ip6tables to allow debug logging +ip6tables_wrapper(){ + cmd_wrapper ip6tables ${IP6TABLES_BINARY} "$@" +} + +# wrapper to call tc to allow debug logging +tc_wrapper(){ + cmd_wrapper tc ${TC_BINARY} "$@" +} + +# wrapper to call ip to allow debug logging +ip_wrapper(){ + cmd_wrapper ip ${IP_BINARY} "$@" +} + +# the actual command execution wrapper +cmd_wrapper(){ + # $1: the symbolic name of the command for informative output + # $2: the name of the binary to call (potentially including the full path) + # $3-$end: the actual arguments for $2 + local CALLERID + local CMD_BINARY + local LAST_ERROR + local RET + local ERRLOG + + CALLERID=$1 ; shift 1 # extract and remove the id string + CMD_BINARY=$1 ; shift 1 # extract and remove the binary + + # Handle silencing of errors from callers + ERRLOG="sqm_error" + if [ "$SILENT" -eq "1" ]; then + ERRLOG="sqm_debug" + sqm_debug "cmd_wrapper: ${CALLERID}: invocation silenced by request, FAILURE either expected or acceptable." + # The busybox shell doesn't understand the concept of an inline variable + # only applying to a single command, so we need to reset SILENT + # afterwards. Ugly, but it works... + SILENT=0 + fi + + sqm_trace "cmd_wrapper: COMMAND: ${CMD_BINARY} $@" + LAST_ERROR=$( ${CMD_BINARY} "$@" 2>&1 ) + RET=$? + + if [ "$RET" -eq "0" ] ; then + sqm_debug "cmd_wrapper: ${CALLERID}: SUCCESS: ${CMD_BINARY} $@" + else + # this went south, try to capture & report more detail + $ERRLOG "cmd_wrapper: ${CALLERID}: FAILURE (${RET}): ${CMD_BINARY} $@" + $ERRLOG "cmd_wrapper: ${CALLERID}: LAST ERROR: ${LAST_ERROR}" + fi + + return $RET +} + + +do_modules() { + for m in $ALL_MODULES; do + [ -d /sys/module/${m} ] || ${INSMOD} $m 2>>${OUTPUT_TARGET} + done +} + +# Write a state file to the filename given as $1. This version will extract all +# variable names defined in defaults.sh and since defaults.sh should contain all +# used variables this should be the complete set. +write_state_file() { + local filename + local awkscript + awkscript='match($0, /[A-Z0-9_]+=/) {print substr($0, RSTART, RLENGTH-1)}' + filename=$1 + shift + awk "$awkscript" ${SQM_LIB_DIR}/defaults.sh | sort -u | while read var; do + val=$(eval echo '$'$var) + echo "$var=\"$val\"" + done > $filename +} + +check_state_dir() { + local PERM + local OWNER + + if [ -z "${SQM_STATE_DIR}" ]; then + SQM_DEBUG=0 sqm_error '$SQM_STATE_DIR is unset - check your config!' + exit 1 + fi + [ -d "${SQM_STATE_DIR}" ] || ( umask 077; mkdir -p "$SQM_STATE_DIR" ) || exit 1 + + if [ ! -w "${SQM_STATE_DIR}" ] || [ ! -x "${SQM_STATE_DIR}" ]; then + SQM_DEBUG=0 sqm_error "Cannot write to state dir '$SQM_STATE_DIR'" + exit 1 + fi + + # OpenWrt doesn't have stat; for now just skip the remaining tests if it's + # not available + command -v stat >/dev/null 2>&1 || return 0 + + PERM="0$(stat -L -c '%a' "${SQM_STATE_DIR}")" + if [ "$((PERM & 0002))" -ne 0 ]; then + SQM_DEBUG=0 sqm_error "State dir '$SQM_STATE_DIR' is world writable; this is unsafe, please fix" + exit 1 + fi + OWNER="$(stat -L -c '%u' "${SQM_STATE_DIR}")" + if [ "$OWNER" -ne "$(id -u)" ]; then + SQM_DEBUG=0 sqm_error "State dir '$SQM_STATE_DIR' is owned by a different user; this is unsafe, please fix" + exit 1 + fi +} + + +# find the ifb device associated with a specific interface, return nothing of no +# ifb is associated with IF +get_ifb_associated_with_if() { + local CUR_IF + local CUR_IFB + local TMP + CUR_IF=$1 + # Stray ' in the comment is a fix for broken editor syntax highlighting + CUR_IFB=$( $TC_BINARY -p filter show parent ffff: dev ${CUR_IF} | grep -o -E ifb'[^)\ ]+' ) # ' + sqm_debug "ifb associated with interface ${CUR_IF}: ${CUR_IFB}" + + # we could not detect an associated IFB for CUR_IF + if [ -z "${CUR_IFB}" ]; then + TMP=$( $TC_BINARY -p filter show parent ffff: dev ${CUR_IF} ) + if [ ! -z "${TMP}" ]; then + # oops, there is output but we failed to properly parse it? Ask for a user report + sqm_error "#---- CUT HERE ----#" + sqm_error "get_ifb_associated_with_if failed to extrect the ifb name from:" + sqm_error $( $TC_BINARY -p filter show parent ffff: dev ${CUR_IF} ) + sqm_error "Please report this as an issue at https://github.com/tohojo/sqm-scripts" + sqm_error "Please copy and paste everything below the cut-here line into your issue report, thanks." + else + sqm_debug "Currently no ifb is associated with ${CUR_IF}, this is normal during starting of the sqm system." + fi + fi + echo ${CUR_IFB} +} + +ifb_name() { + local CUR_IF + local MAX_IF_NAME_LENGTH + local IFB_PREFIX + local NEW_IFB + CUR_IF=$1 + MAX_IF_NAME_LENGTH=15 + IFB_PREFIX="ifb4" + NEW_IFB=$( echo -n "${IFB_PREFIX}${CUR_IF}" | head -c $MAX_IF_NAME_LENGTH ) + + echo ${NEW_IFB} +} + +# if required +create_new_ifb_for_if() { + local NEW_IFB + NEW_IFB=$(ifb_name $1) + create_ifb ${NEW_IFB} + RET=$? + echo $NEW_IFB + return $RET +} + + +# TODO: report failures +create_ifb() { + local CUR_IFB + CUR_IFB=${1} + $IP link add name ${CUR_IFB} type ifb +} + +delete_ifb() { + local CUR_IFB + CUR_IFB=${1} + $IP link set dev ${CUR_IFB} down + $IP link delete ${CUR_IFB} type ifb +} + + +# the best match is either the IFB already associated with the current interface +# or a new named IFB +get_ifb_for_if() { + local CUR_IF + local CUR_IFB + CUR_IF=$1 + # if an ifb is already associated return that + CUR_IFB=$( get_ifb_associated_with_if ${CUR_IF} ) + [ -z "$CUR_IFB" ] && CUR_IFB=$( create_new_ifb_for_if ${CUR_IF} ) + [ -z "$CUR_IFB" ] && sqm_warn "Could not find existing IFB for ${CUR_IF}, nor create a new IFB instead..." + echo ${CUR_IFB} +} + + +# Verify that a qdisc works, and optionally that it is part of a set of +# supported qdiscs. If passed a $2, this function will first check if $1 is in +# that (space-separated) list and return an error if it's not. +# +# note the ingress qdisc is different in that it requires tc qdisc replace dev +# tmp_ifb ingress instead of "root ingress" +verify_qdisc() { + local qdisc + local supported + local ifb + local root_string + local args + local IFB_MTU + local found + local randnum + qdisc=$1 + supported="$2" + randnum=$(tr -cd 0-9a-f < /dev/urandom 2>/dev/null | head -c 5) + ifb=SQM_IFB_$randnum + root_string="root" # this works for most qdiscs + args="" + IFB_MTU=1514 + + if [ -n "$supported" ]; then + found=0 + for q in $supported; do + [ "$qdisc" = "$q" ] && found=1 + done + [ "$found" -eq "1" ] || return 1 + fi + create_ifb $ifb || return 1 + + + case $qdisc in + #ingress is special + ingress) root_string="" ;; + #cannot instantiate tbf without args + tbf) + IFB_MTU=$( get_mtu $ifb ) + IFB_MTU=$(( ${IFB_MTU} + 14 )) # TBF's warning is confused, it says MTU but it checks MTU + 14 + args="limit 1 burst ${IFB_MTU} rate 1kbps" + ;; + esac + + $TC qdisc replace dev $ifb $root_string $qdisc $args + res=$? + if [ "$res" = "0" ] ; then + sqm_debug "QDISC $qdisc is useable." + else + sqm_error "QDISC $qdisc is NOT useable." + fi + delete_ifb $ifb + return $res +} + + +get_htb_adsll_string() { + ADSLL="" + if [ "$LLAM" = "htb_private" -a "$LINKLAYER" != "none" ]; then + # HTB defaults to MTU 1600 and an implicit fixed TSIZE of 256, but HTB + # as of around 3.10.0 does not actually use a table in the kernel + ADSLL="mpu ${STAB_MPU} linklayer ${LINKLAYER} overhead ${OVERHEAD} mtu ${STAB_MTU}" + sqm_debug "ADSLL: ${ADSLL}" + fi + echo ${ADSLL} +} + +get_stab_string() { + local STABSTRING + local TMP_LLAM + STABSTRING="" + TMP_LLAM=${LLAM} + if [ "${LLAM}" = "default" -a "$QDISC" != "cake" ]; then + sqm_debug "LLA: default link layer adjustment method for !cake is tc_stab" + TMP_LLAM="tc_stab" + fi + + if [ "${TMP_LLAM}" = "tc_stab" -a "$LINKLAYER" != "none" ]; then + STABSTRING="stab mtu ${STAB_MTU} tsize ${STAB_TSIZE} mpu ${STAB_MPU} overhead ${OVERHEAD} linklayer ${LINKLAYER}" + sqm_debug "STAB: ${STABSTRING}" + fi + echo ${STABSTRING} +} + +# cake knows how to handle ATM and per packet overhead, so expose and use this... +get_cake_lla_string() { + local STABSTRING + local TMP_LLAM + STABSTRING="" + TMP_LLAM=${LLAM} + if [ "${LLAM}" = "default" -a "$QDISC" = "cake" ]; then + sqm_debug "LLA: default link layer adjustment method for cake is cake" + TMP_LLAM="cake" + fi + + if [ "${TMP_LLAM}" = "cake" -a "${LINKLAYER}" != "none" ]; then + if [ "${LINKLAYER}" = "atm" ]; then + STABSTRING="atm" + fi + + STABSTRING="${STABSTRING} overhead ${OVERHEAD} mpu ${STAB_MPU}" + + sqm_debug "cake link layer adjustments: ${STABSTRING}" + fi + echo ${STABSTRING} +} + + +# centralize the implementation for the default sqm_start sqeuence +# the individual sqm_start function only need to do the individually +# necessary checking. +# This expects the calling script to supply both an egress() and ingress() function +# and will warn if they are missing +sqm_start_default() { + #sqm_error "sqm_start_default" + [ -n "$IFACE" ] || return 1 + + # reset the iptables trace log + ipt_log_restart + + if fn_exists sqm_prepare_script ; then + sqm_debug "sqm_start_default: starting sqm_prepare_script" + sqm_prepare_script + else + sqm_debug "sqm_start_default: no sqm_prepare_script function found, proceeding without." + fi + + do_modules + verify_qdisc $QDISC || return 1 + sqm_debug "sqm_start_default: Starting ${SCRIPT}" + + [ -z "$DEV" ] && DEV=$( get_ifb_for_if ${IFACE} ) + + if [ "${UPLINK}" -ne 0 ]; + then + CUR_DIRECTION="egress" + fn_exists egress && egress || sqm_warn "sqm_start_default: ${SCRIPT} lacks an egress() function" + #egress + sqm_debug "sqm_start_default: egress shaping activated" + else + sqm_debug "sqm_start_default: egress shaping deactivated" + SILENT=1 $TC qdisc del dev ${IFACE} root + fi + if [ "${DOWNLINK}" -ne 0 ]; + then + CUR_DIRECTION="ingress" + verify_qdisc ingress "ingress" || return 1 + fn_exists ingress && ingress || sqm_warn "sqm_start_default: ${SCRIPT} lacks an ingress() function" + #ingress + sqm_debug "sqm_start_default: ingress shaping activated" + else + sqm_debug "sqm_start_default: ingress shaping deactivated" + SILENT=1 $TC qdisc del dev ${DEV} root + SILENT=1 $TC qdisc del dev ${IFACE} ingress + fi + + return 0 +} + + +sqm_stop() { + if [ "${DOWNLINK}" -ne 0 ]; then + $TC qdisc del dev $IFACE ingress + $TC qdisc del dev $IFACE root + [ -n "$CUR_IFB" ] && $TC qdisc del dev $CUR_IFB root + [ -n "$CUR_IFB" ] && sqm_debug "${0}: ${CUR_IFB} shaper deleted" + fi + + # undo accumulated ipt commands during shutdown + ipt_log_rewind + # reset the iptables trace log + ipt_log_restart + + [ -n "$CUR_IFB" ] && $IP link set dev ${CUR_IFB} down + [ -n "$CUR_IFB" ] && $IP link delete ${CUR_IFB} type ifb + [ -n "$CUR_IFB" ] && sqm_debug "${0}: ${CUR_IFB} interface deleted" +} + +# Note this has side effects on the prio variable +# and depends on the interface global too +fc() { + $TC filter add dev $interface protocol ip parent $1 prio $prio u32 match ip tos $2 0xfc classid $3 + prio=$(($prio + 1)) + $TC filter add dev $interface protocol ipv6 parent $1 prio $prio u32 match ip6 priority $2 0xfc classid $3 + prio=$(($prio + 1)) +} + + +# allow better control over HTB's quantum variable +# this controlls how many bytes htb ties to deque from the current tier before +# switching to the next, if this is large mixing between pririty tiers will be +# lumpy, but at a lower CPU cost. In first approximation quantum should not be +# larger than burst. +get_htb_quantum() { + local HTB_MTU + local BANDWIDTH + local DURATION_US + local MIN_QUANTUM + local QUANTUM + HTB_MTU=$( get_mtu $1 ) + BANDWIDTH=$2 + DURATION_US=$3 + + sqm_debug "get_htb_quantum: 1: ${1}, 2: ${2}, 3: ${3}" + + if [ -z "${DURATION_US}" ] ; then + DURATION_US=${SHAPER_QUANTUM_DUR_US} # the duration of the burst in microseconds + sqm_warn "get_htb_quantum (by duration): Defaulting to ${DURATION_US} microseconds." + fi + + if [ -n "${HTB_MTU}" -a "${DURATION_US}" -gt "0" ] ; then + QUANTUM=$( get_burst ${HTB_MTU} ${BANDWIDTH} ${DURATION_US} ) + fi + + if [ -z "$QUANTUM" ]; then + MIN_QUANTUM=$(( ${MTU} + 48 )) # add 48 bytes to MTU for the ovehead + MIN_QUANTUM=$(( ${MIN_QUANTUM} + 47 )) # now do ceil(Min_BURST / 48) * 53 in shell integer arithmic + MIN_QUANTUM=$(( ${MIN_QUANTUM} / 48 )) + MIN_QUANTUM=$(( ${MIN_QUANTUM} * 53 )) # for MTU 1489 to 1536 this will result in MIN_BURST = 1749 Bytes + sqm_warn "get_htb_quantum: 0 bytes quantum will not work, defaulting to one ATM/AAL5 expanded MTU packet with overhead: ${MIN_QUANTUM}" + echo ${MIN_QUANTUM} + else + echo ${QUANTUM} + fi +} + + + + +# try to define the burst parameter in the duration required to transmit a burst +# at the configured bandwidth conceptuallly the matching quantum for this burst +# should be BURST/number_of_tiers to give each htb tier a chance to dequeue into +# each burst, but that most likely will end up with a somewhat too small quantum +# note: to get htb to report the configured burst/cburt one needs to issue the +# following command (for ifbpppoe-wan): +# tc -d class show dev ifb4pppoe-wan +get_burst() { + local MTU + local BANDWIDTH + local SHAPER_BURST_US + local MIN_BURST + local BURST + MTU=$1 + BANDWIDTH=$2 # note bandwidth is always given in kbps + SHAPER_BURST_US=$3 + + sqm_debug "get_burst: 1: ${1}, 2: ${2}, 3: ${3}" + + if [ -z "${SHAPER_BURST_US}" ] ; then + SHAPER_BURST_US=1000 # the duration of the burst in microseconds + sqm_warn "get_burst (by duration): Defaulting to ${SHAPER_BURST_US} microseconds bursts." + fi + + # let's assume ATM/AAL5 to be the worst case encapsulation + # and 48 Bytes a reasonable worst case per packet overhead + MIN_BURST=$(( ${MTU} + 48 )) # add 48 bytes to MTU for the ovehead + MIN_BURST=$(( ${MIN_BURST} + 47 )) # now do ceil(Min_BURST / 48) * 53 in shell integer arithmic + MIN_BURST=$(( ${MIN_BURST} / 48 )) + MIN_BURST=$(( ${MIN_BURST} * 53 )) # for MTU 1489 to 1536 this will result in MIN_BURST = 1749 Bytes + + # htb/tbf expect burst to be specified in bytes, while bandwidth is in kbps + BURST=$(( ((${SHAPER_BURST_US} * ${BANDWIDTH}) / 8000) )) + + if [ ${BURST} -lt ${MIN_BURST} ] ; then + sqm_log "get_burst (by duration): the calculated burst/quantum size of ${BURST} bytes was below the minimum of ${MIN_BURST} bytes." + BURST=${MIN_BURST} + fi + + sqm_debug "get_burst (by duration): BURST [Byte]: ${BURST}, BANDWIDTH [Kbps]: ${BANDWIDTH}, DURATION [us]: ${SHAPER_BURST_US}" + + echo ${BURST} +} + + +# Create optional burst parameters to leap over CPU interupts when the CPU is +# severly loaded. We need to be conservative though. +get_htb_burst() { + local HTB_MTU + local BANDWIDTH + local DURATION_US + local BURST + HTB_MTU=$( get_mtu $1 ) + BANDWIDTH=$2 + DURATION_US=$3 + + sqm_debug "get_htb_burst: 1: ${1}, 2: ${2}, 3: ${3}" + + if [ -z "${DURATION_US}" ] ; then + DURATION_US=${SHAPER_BURST_DUR_US} # the duration of the burst in microseconds + sqm_warn "get_htb_burst (by duration): Defaulting to ${SHAPER_BURST_DUR_US} microseconds." + fi + + if [ -n "${HTB_MTU}" -a "${DURATION_US}" -gt "0" ] ; then + BURST=$( get_burst ${HTB_MTU} ${BANDWIDTH} ${DURATION_US} ) + fi + + if [ -z "$BURST" ]; then + sqm_debug "get_htb_burst: Default Burst, HTB will use MTU plus shipping and handling" + else + echo burst $BURST cburst $BURST + fi +} + +# For a default PPPoE link this returns 1492 just as expected but I fear we +# actually need the wire size of the whole thing not so much the MTU +get_mtu() { + CUR_MTU=$(cat /sys/class/net/$1/mtu) + sqm_debug "IFACE: ${1} MTU: ${CUR_MTU}" + echo ${CUR_MTU} +} + +# Set the autoflow variable to 1 if you want to limit the number of flows +# otherwise the default of 1024 will be used for all Xfq_codel qdiscs. + +get_flows() { + case $QDISC in + codel|ns2_codel|pie|*fifo|pfifo_fast) ;; + fq_codel|*fq_codel|sfq) echo flows $( get_flows_count ${1} ) ;; + esac +} + +get_flows_count() { + if [ "${AUTOFLOW}" -eq "1" ]; then + FLOWS=8 + [ $1 -gt 999 ] && FLOWS=16 + [ $1 -gt 2999 ] && FLOWS=32 + [ $1 -gt 7999 ] && FLOWS=48 + [ $1 -gt 9999 ] && FLOWS=64 + [ $1 -gt 19999 ] && FLOWS=128 + [ $1 -gt 39999 ] && FLOWS=256 + [ $1 -gt 69999 ] && FLOWS=512 + [ $1 -gt 99999 ] && FLOWS=1024 + case $QDISC in + codel|ns2_codel|pie|*fifo|pfifo_fast) ;; + fq_codel|*fq_codel|sfq) echo $FLOWS ;; + esac + else + case $QDISC in + codel|ns2_codel|pie|*fifo|pfifo_fast) ;; + fq_codel|*fq_codel|sfq) echo 1024 ;; + esac + fi +} + +# set the target parameter, also try to only take well formed inputs +# Note, the link bandwidth in the current direction (ingress or egress) +# is required to adjust the target for slow links +get_target() { + local CUR_TARGET + local CUR_LINK_KBPS + CUR_TARGET=${1} + CUR_LINK_KBPS=${2} + [ ! -z "$CUR_TARGET" ] && sqm_debug "cur_target: ${CUR_TARGET} cur_bandwidth: ${CUR_LINK_KBPS}" + CUR_TARGET_STRING= + # either e.g. 100ms or auto + CUR_TARGET_VALUE=$( echo ${CUR_TARGET} | grep -o -e \^'[[:digit:]]\+' ) + CUR_TARGET_UNIT=$( echo ${CUR_TARGET} | grep -o -e '[[:alpha:]]\+'\$ ) + + AUTO_TARGET= + UNIT_VALID= + + case $QDISC in + *codel|*pie) + if [ ! -z "${CUR_TARGET_VALUE}" -a ! -z "${CUR_TARGET_UNIT}" ]; + then + case ${CUR_TARGET_UNIT} in + # permissible units taken from: tc_util.c get_time() + s|sec|secs|ms|msec|msecs|us|usec|usecs) + CUR_TARGET_STRING="target ${CUR_TARGET_VALUE}${CUR_TARGET_UNIT}" + UNIT_VALID="1" + ;; + esac + fi + # empty field in GUI or undefined GUI variable now defaults to auto + if [ -z "${CUR_TARGET_VALUE}" -a -z "${CUR_TARGET_UNIT}" ]; + then + if [ ! -z "${CUR_LINK_KBPS}" ]; then + TMP_TARGET_US=$( adapt_target_to_slow_link $CUR_LINK_KBPS ) + TMP_INTERVAL_STRING=$( adapt_interval_to_slow_link $TMP_TARGET_US ) + CUR_TARGET_STRING="target ${TMP_TARGET_US}us ${TMP_INTERVAL_STRING}" + AUTO_TARGET="1" + sqm_debug "get_target defaulting to auto." + else + sqm_warn "required link bandwidth in kbps not passed to get_target()." + fi + fi + # but still allow explicit use of the keyword auto for backward compatibility + case ${CUR_TARGET_UNIT} in + auto|Auto|AUTO) + if [ ! -z "${CUR_LINK_KBPS}" ]; then + TMP_TARGET_US=$( adapt_target_to_slow_link $CUR_LINK_KBPS ) + TMP_INTERVAL_STRING=$( adapt_interval_to_slow_link $TMP_TARGET_US ) + CUR_TARGET_STRING="target ${TMP_TARGET_US}us ${TMP_INTERVAL_STRING}" + AUTO_TARGET="1" + else + sqm_warn "required link bandwidth in kbps not passed to get_target()." + fi + ;; + esac + + case ${CUR_TARGET_UNIT} in + default|Default|DEFAULT) + if [ ! -z "${CUR_LINK_KBPS}" ]; then + CUR_TARGET_STRING="" # return nothing so the default target is not over-ridden... + AUTO_TARGET="1" + sqm_debug "get_target using qdisc default, no explicit target string passed." + else + sqm_warn "required link bandwidth in kbps not passed to get_target()." + fi + ;; + esac + if [ ! -z "${CUR_TARGET}" ]; then + if [ -z "${CUR_TARGET_VALUE}" -o -z "${UNIT_VALID}" ]; then + [ -z "$AUTO_TARGET" ] && sqm_warn "${CUR_TARGET} is not a well formed tc target specifier; e.g.: 5ms (or s, us), or one of the strings auto or default." + fi + fi + ;; + esac + echo $CUR_TARGET_STRING +} + +# for low bandwidth links fq_codels default target of 5ms does not work too well +# so increase target for slow links (note below roughly 2500kbps a single packet +# will take more than 5 ms to be tansfered over the wire) +adapt_target_to_slow_link() { + LINK_BW=$1 + # for ATM the worst case expansion including overhead seems to be 33 clls of + # 53 bytes each + MAX_DELAY=$(( 1000 * 1000 * 33 * 53 * 8 / 1000 )) # Max delay in us at 1kbps + TARGET=$(( ${MAX_DELAY} / ${LINK_BW} )) # note this truncates the decimals + + # do not change anything for fast links + [ "$TARGET" -lt 5000 ] && TARGET=5000 + case ${QDISC} in + *codel|pie) + echo "${TARGET}" + ;; + esac +} + +# codel looks at a whole interval to figure out wether observed latency stayed +# below target if target >= interval that will not work well, so increase +# interval by the same amonut that target got increased +adapt_interval_to_slow_link() { + TARGET=$1 + case ${QDISC} in + *codel) + # Note this is not following codel theory to well as target should + # be 5-10% of interval and the simple addition does not conserve + # that relationship + INTERVAL=$(( (100 - 5) * 1000 + ${TARGET} )) + echo "interval ${INTERVAL}us" + ;; + pie) + ## not sure if pie needs this, probably not + #TUPDATE=$(( (30 - 20) * 1000 + ${TARGET} )) + #echo "tupdate ${TUPDATE}us" + ;; + esac +} + + +# set quantum parameter if available for this qdisc +get_quantum() { + case $QDISC in + *fq_codel|fq_pie|drr) echo quantum $1 ;; + *) ;; + esac +} + +# only show limits to qdiscs that can handle them... +# Note that $LIMIT contains the default limit +get_limit() { + CURLIMIT=$1 + case $QDISC in + *codel|*pie|pfifo_fast|sfq|pfifo) [ -z ${CURLIMIT} ] && CURLIMIT=${LIMIT} # global default limit + ;; + bfifo) [ -z "$CURLIMIT" ] && [ ! -z "$LIMIT" ] && CURLIMIT=$(( ${LIMIT} * $( cat /sys/class/net/${IFACE}/mtu ) )) # bfifo defaults to txquelength * MTU, + ;; + *) sqm_warn "qdisc ${QDISC} does not support a limit" + ;; + esac + sqm_debug "get_limit: $1 CURLIMIT: ${CURLIMIT}" + + if [ ! -z "$CURLIMIT" ]; then + echo "limit ${CURLIMIT}" + fi +} + +get_ecn() { + CURECN=$1 + case ${CURECN} in + ECN) + case $QDISC in + *codel|*pie|*red) + CURECN=ecn + ;; + *) + CURECN="" + ;; + esac + ;; + NOECN) + case $QDISC in + *codel|*pie|*red) + CURECN=noecn + ;; + *) + CURECN="" + ;; + esac + ;; + *) + sqm_warn "ecn value $1 not handled" + ;; + esac + sqm_debug "get_ECN: $1 CURECN: ${CURECN} IECN: ${IECN} EECN: ${EECN}" + echo ${CURECN} + +} + +# This could be a complete diffserv implementation + +diffserv() { + + interface=$1 + prio=1 + + # Catchall + + $TC filter add dev $interface parent 1:0 protocol all prio 999 u32 \ + match ip protocol 0 0x00 flowid 1:12 + + # Find the most common matches fast + + fc 1:0 0x00 1:12 # BE + fc 1:0 0x20 1:13 # CS1 + fc 1:0 0x10 1:11 # IMM + fc 1:0 0xb8 1:11 # EF + fc 1:0 0xc0 1:11 # CS3 + fc 1:0 0xe0 1:11 # CS6 + fc 1:0 0x90 1:11 # AF42 (mosh) + + # Arp traffic + $TC filter add dev $interface protocol arp parent 1:0 prio $prio handle 500 fw flowid 1:11 + + prio=$(($prio + 1)) +} + +eth_setup() { + ethtool -K $IFACE gso off + ethtool -K $IFACE tso off + ethtool -K $IFACE ufo off + ethtool -K $IFACE gro off + + if [ -e /sys/class/net/$IFACE/queues/tx-0/byte_queue_limits ]; then + for i in /sys/class/net/$IFACE/queues/tx-*/byte_queue_limits + do + echo $(( 4 * $( get_mtu ${IFACE} ) )) > $i/limit_max + done + fi +} diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/layer_cake.qos b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/layer_cake.qos new file mode 100644 index 0000000..27d8163 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/layer_cake.qos @@ -0,0 +1,52 @@ +# Cero3 Shaper +# A cake shaper and AQM solution that allows several diffserv marking schemes +# for ethernet gateways + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Copyright (C) 2012-5 Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller + + +#sm: TODO pass in the cake diffserv keyword + +. ${SQM_LIB_DIR}/defaults.sh +QDISC=cake + +# Default traffic classication is passed in INGRESS_CAKE_OPTS and EGRESS_CAKE_OPTS, defined in defaults.sh now + + +egress() { + SILENT=1 $TC qdisc del dev $IFACE root + $TC qdisc add dev $IFACE root $( get_stab_string ) cake \ + bandwidth ${UPLINK}kbit $( get_cake_lla_string ) ${EGRESS_CAKE_OPTS} ${EQDISC_OPTS} + +} + + +ingress() { + + SILENT=1 $TC qdisc del dev $IFACE handle ffff: ingress + $TC qdisc add dev $IFACE handle ffff: ingress + + SILENT=1 $TC qdisc del dev $DEV root + + [ "$IGNORE_DSCP_INGRESS" -eq "1" ] && INGRESS_CAKE_OPTS="$INGRESS_CAKE_OPTS besteffort" + [ "$ZERO_DSCP_INGRESS" -eq "1" ] && INGRESS_CAKE_OPTS="$INGRESS_CAKE_OPTS wash" + + $TC qdisc add dev $DEV root $( get_stab_string ) cake \ + bandwidth ${DOWNLINK}kbit $( get_cake_lla_string ) ${INGRESS_CAKE_OPTS} ${IQDISC_OPTS} + + $IP link set dev $DEV up + + # redirect all IP packets arriving in $IFACE to ifb0 + + $TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \ + match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV +} + +sqm_prepare_script() { + do_modules + verify_qdisc $QDISC "cake" || return 1 +} diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/layer_cake.qos.help b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/layer_cake.qos.help new file mode 100644 index 0000000..1cab3ed --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/layer_cake.qos.help @@ -0,0 +1,4 @@ +This uses the cake qdisc as a replacement for both htb as shaper and fq_codel as leaf qdisc. +This exercises cake's diffserv profile(s) as different "layers" of priority. +This script requires that cake is selected as qdisc, and forces its usage. +See: http://www.bufferbloat.net/projects/codel/wiki/Cake for more information diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/piece_of_cake.qos b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/piece_of_cake.qos new file mode 100644 index 0000000..ac65eda --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/piece_of_cake.qos @@ -0,0 +1,52 @@ +# Cero3 Simple Shaper +# A 1 tin cake shaper for +# ethernet gateways. This is nearly the simplest possible + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Copyright (C) 2012-5 Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller + + +. ${SQM_LIB_DIR}/defaults.sh +QDISC=cake + + +# to keep this as simple as possible we ignore the *_CAKE_OPTS from defaults.sh +INGRESS_CAKE_OPTS="besteffort" +EGRESS_CAKE_OPTS="besteffort" + + +egress() { + sqm_debug "egress" + SILENT=1 $TC qdisc del dev $IFACE root + $TC qdisc add dev $IFACE root $( get_stab_string ) cake \ + bandwidth ${UPLINK}kbit $( get_cake_lla_string ) ${EGRESS_CAKE_OPTS} ${EQDISC_OPTS} +} + + +ingress() { + sqm_debug "ingress" + + SILENT=1 $TC qdisc del dev $IFACE handle ffff: ingress + $TC qdisc add dev $IFACE handle ffff: ingress + SILENT=1 $TC qdisc del dev $DEV root + + [ "$ZERO_DSCP_INGRESS" -eq "1" ] && INGRESS_CAKE_OPTS="$INGRESS_CAKE_OPTS wash" + + $TC qdisc add dev $DEV root $( get_stab_string ) cake \ + bandwidth ${DOWNLINK}kbit $( get_cake_lla_string ) ${INGRESS_CAKE_OPTS} ${IQDISC_OPTS} + + $IP link set dev $DEV up + + # redirect all IP packets arriving in $IFACE to ifb0 + + $TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \ + match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV +} + +sqm_prepare_script() { + do_modules + verify_qdisc $QDISC "cake" || return 1 +} diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/piece_of_cake.qos.help b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/piece_of_cake.qos.help new file mode 100644 index 0000000..b95e9be --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/piece_of_cake.qos.help @@ -0,0 +1,4 @@ +This just uses the cake qdisc as a replacement for both htb as shaper and fq_codel as leaf qdisc. +It just does not come any simpler than this, in other words it truely is a "piece of cake". +This script requires that cake is selected as qdisc, and forces its usage. +See: http://www.bufferbloat.net/projects/codel/wiki/Cake for more information diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/run.sh b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/run.sh new file mode 100644 index 0000000..6f55ca7 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/run.sh @@ -0,0 +1,130 @@ +#!/bin/sh + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Copyright (C) 2012-4 Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller + + +. /lib/functions.sh + +. /etc/sqm/sqm.conf +. ${SQM_LIB_DIR}/functions.sh + +ACTION="${1:-start}" +RUN_IFACE="$2" +LOCKDIR="${SQM_STATE_DIR}/sqm-run.lock" + +check_state_dir +[ -d "${SQM_QDISC_STATE_DIR}" ] || ${SQM_LIB_DIR}/update-available-qdiscs + +stop_statefile() { + local f + f="$1" + # Source the state file prior to stopping; we need the variables saved in + # there. + [ -f "$f" ] && ( . "$f"; + IFACE=$IFACE SCRIPT=$SCRIPT SQM_DEBUG=$SQM_DEBUG \ + SQM_DEBUG_LOG=$SQM_DEBUG_LOG \ + SQM_VERBOSITY_MAX=$SQM_VERBOSITY_MAX \ + SQM_VERBOSITY_MIN=$SQM_VERBOSITY_MIN \ + OUTPUT_TARGET=$OUTPUT_TARGET ${SQM_LIB_DIR}/stop-sqm ) +} + +start_sqm_section() { + local section + section="$1" + export IFACE=$(config_get "$section" interface) + + [ -z "$RUN_IFACE" -o "$RUN_IFACE" = "$IFACE" ] || return + [ "$(config_get "$section" enabled)" -eq 1 ] || return 0 + [ -f "${SQM_STATE_DIR}/${IFACE}.state" ] && return + + export UPLINK=$(config_get "$section" upload) + export DOWNLINK=$(config_get "$section" download) + export LLAM=$(config_get "$section" linklayer_adaptation_mechanism) + export LINKLAYER=$(config_get "$section" linklayer) + export OVERHEAD=$(config_get "$section" overhead) + export STAB_MTU=$(config_get "$section" tcMTU) + export STAB_TSIZE=$(config_get "$section" tcTSIZE) + export STAB_MPU=$(config_get "$section" tcMPU) + export ILIMIT=$(config_get "$section" ilimit) + export ELIMIT=$(config_get "$section" elimit) + export ITARGET=$(config_get "$section" itarget) + export ETARGET=$(config_get "$section" etarget) + export IECN=$(config_get "$section" ingress_ecn) + export EECN=$(config_get "$section" egress_ecn) + export IQDISC_OPTS=$(config_get "$section" iqdisc_opts) + export EQDISC_OPTS=$(config_get "$section" eqdisc_opts) + export TARGET=$(config_get "$section" target) + export QDISC=$(config_get "$section" qdisc) + export SCRIPT=$(config_get "$section" script) + + # The UCI names for these two variables are confusing and should have been + # changed ages ago. For now, keep the bad UCI names but use meaningful + # variable names in the scripts to not break user configs. + export ZERO_DSCP_INGRESS=$(config_get "$section" squash_dscp) + export IGNORE_DSCP_INGRESS=$(config_get "$section" squash_ingress) + + # If SQM_DEBUG or SQM_VERBOSITY_* were passed in via the command line make + # them available to the other scripts this allows to override sqm's log + # level as set in the GUI for quick debugging without GUI accesss. + export SQM_DEBUG=${SQM_DEBUG:-$(config_get "$section" debug_logging)} + export SQM_VERBOSITY_MAX=${SQM_VERBOSITY_MAX:-$(config_get "$section" verbosity)} + export SQM_VERBOSITY_MIN + + "${SQM_LIB_DIR}/start-sqm" +} + +release_lock() { + PID=$(cat "$LOCKDIR/pid") + if [ "$PID" -ne "$$" ]; then + sqm_error "Trying to release lock with wrong PID $PID != $$" + return 1 + fi + + rm -rf "$LOCKDIR" + return 0 +} + +take_lock() { + + if mkdir "$LOCKDIR" 2>/dev/null; then + sqm_trace "Acquired run lock" + echo $$ > "$LOCKDIR/pid" + + trap release_lock 0 + return 0 + fi + PID=$(cat "$LOCKDIR/pid") + sqm_warn "Unable to get run lock - already held by $PID" + return 1 +} + +MAX_TRIES=10 +tries=$MAX_TRIES +while ! take_lock; do + sleep 1 + tries=$((tries - 1)) + if [ "$tries" -eq 0 ]; then + sqm_error "Giving up on getting lock after $MAX_TRIES attempts" + sqm_error "This is a bug; please report it at https://github.com/tohojo/sqm-scripts/issues" + sqm_error "Then, to re-enable sqm-scripts, manually remove $LOCKDIR" + exit 1 + fi +done + +if [ "$ACTION" = "stop" ]; then + if [ -z "$RUN_IFACE" ]; then + # Stopping all active interfaces + for f in ${SQM_STATE_DIR}/*.state; do + stop_statefile "$f" + done + else + stop_statefile "${SQM_STATE_DIR}/${RUN_IFACE}.state" + fi +else + config_load sqm + config_foreach start_sqm_section +fi diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simple.qos b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simple.qos new file mode 100644 index 0000000..55f3cdf --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simple.qos @@ -0,0 +1,234 @@ +################################################################################ +# simple.qos (Cero3 Shaper) +# +# Abstract: +# This is a three band fq_codel and ipv6 enabled shaping script for Ethernet +# gateways. Compared to the complexity that debloat had become this cleanly +# shows a means of going from diffserv marking to prioritization using the +# current tools ip(6)tables and tc. We should note that the complexity of +# debloat exists for a reason, and it is expected that script is run first to +# setup various other parameters such as BQL and ethtool. +# +# (Assume the debloat script has setup the other interfaces.) +# +# Notes: +# This does the right thing with ipv6 traffic. It also tries to leverage +# diffserv to some sane extent. In particular, the 'priority' queue is limited +# to 33% of the total, so EF, and IMM traffic cannot starve other types. The +# rfc suggested 30%. 30% is probably a lot in today's world. +# +# References: +# This alternate shaper attempts to go for 1/u performance in a clever way +# http://git.coverfire.com/?p=linux-qos-scripts.git;a=blob;f=src-3tos.sh;hb=HEAD +# +################################################################################ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Copyright (C) 2012-2016 +# Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller +# +################################################################################ + +. ${SQM_LIB_DIR}/defaults.sh + +################################################################################ + +ipt_setup() { + + ipt -t mangle -N QOS_MARK_${IFACE} + + case $QDISC in + cake*) + sqm_debug "cake does all the diffserv work - no need for iptables rules" + ;; + *) + ipt -t mangle -A QOS_MARK_${IFACE} -j MARK --set-mark 0x2/${IPT_MASK} + # You can go further with classification but... + ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class CS1 -j MARK --set-mark 0x3/${IPT_MASK} + ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class CS6 -j MARK --set-mark 0x1/${IPT_MASK} + ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class EF -j MARK --set-mark 0x1/${IPT_MASK} + ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class AF42 -j MARK --set-mark 0x1/${IPT_MASK} + ipt -t mangle -A QOS_MARK_${IFACE} -m tos --tos Minimize-Delay -j MARK --set-mark 0x1/${IPT_MASK} + ;; + esac + + # Turn it on. Preserve classification if already performed + # + #sm: is it correct to do this in $IFACE? Should ingress not be on $DEV? since HTB acts on $DEV? + # + # ZERO also does not work on $DEV (that is the IFB will still see the + # incoming ToS bits whether we squash or not) + # + # ZERO is still useful to protect internal machines... + if [ "$ZERO_DSCP_INGRESS" = "1" ]; then + sqm_debug "Squashing differentiated services code points (DSCP) from ingress." + ipt -t mangle -I PREROUTING -i $IFACE -m dscp ! --dscp 0 -j DSCP --set-dscp-class be + else + sqm_debug "Keeping differentiated services code points (DSCP) from ingress." + ipt -t mangle -A PREROUTING -i $IFACE -m mark --mark 0x00/${IPT_MASK} -g QOS_MARK_${IFACE} + fi + + ipt -t mangle -A POSTROUTING -o $IFACE -m mark --mark 0x00/${IPT_MASK} -g QOS_MARK_${IFACE} + + # The Syn optimization was nice but fq_codel does it for us + # ipt -t mangle -A PREROUTING -i s+ -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j MARK --set-mark 0x01 + # Not sure if this will work. Encapsulation is a problem period + + ipt -t mangle -I PREROUTING -i vtun+ -p tcp -j MARK --set-mark 0x2/${IPT_MASK} # tcp tunnels need ordering + + # Emanating from router, do a little more optimization + # but don't bother with it too much. + + ipt -t mangle -A OUTPUT -p udp -m multiport --ports 123,53 -j DSCP --set-dscp-class AF42 + + #Not clear if the second line is needed + #ipt -t mangle -A OUTPUT -o $IFACE -g QOS_MARK_${IFACE} + +} + + + +cake_egress() +{ + $TC qdisc add dev $IFACE root `get_stab_string` $QDISC bandwidth ${CEIL}kbit `get_cake_lla_string` ${EQDISC_OPTS} +} + +egress() { + + CEIL=${UPLINK} + PRIO_RATE=`expr $CEIL / 3` # Ceiling for prioirty + BE_RATE=`expr $CEIL / 6` # Min for best effort + BK_RATE=`expr $CEIL / 6` # Min for background + BE_CEIL=`expr $CEIL - 16` # A little slop at the top + + LQ="quantum `get_htb_quantum $IFACE $CEIL ${ESHAPER_QUANTUM_DUR_US}`" + BURST="`get_htb_burst $IFACE $CEIL ${ESHAPER_BURST_DUR_US}`" + + SILENT=1 $TC qdisc del dev $IFACE root + + case $QDISC in + cake*) cake_egress; return;; + esac + + $TC qdisc add dev $IFACE root handle 1: `get_stab_string` htb default 12 + $TC class add dev $IFACE parent 1: classid 1:1 htb $LQ rate ${CEIL}kbit ceil ${CEIL}kbit $BURST `get_htb_adsll_string` + $TC class add dev $IFACE parent 1:1 classid 1:11 htb $LQ rate 128kbit ceil ${PRIO_RATE}kbit prio 1 `get_htb_adsll_string` + $TC class add dev $IFACE parent 1:1 classid 1:12 htb $LQ rate ${BE_RATE}kbit ceil ${BE_CEIL}kbit $BURST prio 2 `get_htb_adsll_string` + $TC class add dev $IFACE parent 1:1 classid 1:13 htb $LQ rate ${BK_RATE}kbit ceil ${BE_CEIL}kbit $BURST prio 3 `get_htb_adsll_string` + + $TC qdisc add dev $IFACE parent 1:11 handle 110: $QDISC \ + `get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_quantum 300` `get_flows ${PRIO_RATE}` ${EQDISC_OPTS} + $TC qdisc add dev $IFACE parent 1:12 handle 120: $QDISC \ + `get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_quantum 300` `get_flows ${BE_RATE}` ${EQDISC_OPTS} + $TC qdisc add dev $IFACE parent 1:13 handle 130: $QDISC \ + `get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_quantum 300` `get_flows ${BK_RATE}` ${EQDISC_OPTS} + + # Need a catchall rule + + $TC filter add dev $IFACE parent 1:0 protocol all prio 999 u32 \ + match ip protocol 0 0x00 flowid 1:12 + + # FIXME should probably change the filter here to do pre-nat + + $TC filter add dev $IFACE parent 1:0 protocol ip prio 1 handle 1/${IPT_MASK} fw classid 1:11 + $TC filter add dev $IFACE parent 1:0 protocol ip prio 2 handle 2/${IPT_MASK} fw classid 1:12 + $TC filter add dev $IFACE parent 1:0 protocol ip prio 3 handle 3/${IPT_MASK} fw classid 1:13 + + # ipv6 support. Note that the handle indicates the fw mark bucket that is looked for + + $TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 4 handle 1/${IPT_MASK} fw classid 1:11 + $TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 5 handle 2/${IPT_MASK} fw classid 1:12 + $TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 6 handle 3/${IPT_MASK} fw classid 1:13 + + # Arp traffic + + $TC filter add dev $IFACE parent 1:0 protocol arp prio 7 handle 1/${IPT_MASK} fw classid 1:11 + + # ICMP traffic - Don't impress your friends. Deoptimize to manage ping floods + # better instead + + $TC filter add dev $IFACE parent 1:0 protocol ip prio 8 \ + u32 match ip protocol 1 0xff flowid 1:13 + + $TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 9 \ + u32 match ip protocol 1 0xff flowid 1:13 +} + + +cake_ingress() +{ + CAKEARGS= + [ "$IGNORE_DSCP_INGRESS" = "1" ] && CAKEARGS="$CAKEARGS besteffort" + $TC qdisc add dev $DEV root `get_stab_string` $QDISC bandwidth ${DOWNLINK}kbit \ + $CAKEARGS `get_cake_lla_string` ${IQDISC_OPTS} + + $IP link set dev $DEV up + + # redirect all IP packets arriving in $IFACE to $DEV + + $TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \ + match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV +} + +ingress() { + + CEIL=$DOWNLINK + PRIO_RATE=`expr $CEIL / 3` # Ceiling for prioirty + BE_RATE=`expr $CEIL / 6` # Min for best effort + BK_RATE=`expr $CEIL / 6` # Min for background + BE_CEIL=`expr $CEIL - 16` # A little slop at the top + + LQ="quantum `get_htb_quantum $IFACE $CEIL ${ISHAPER_QUANTUM_DUR_US}`" + BURST="`get_htb_burst $IFACE $CEIL ${ISHAPER_BURST_DUR_US}`" + + SILENT=1 $TC qdisc del dev $IFACE handle ffff: ingress + $TC qdisc add dev $IFACE handle ffff: ingress + + SILENT=1 $TC qdisc del dev $DEV root + + case $QDISC in + cake*) cake_ingress; return ;; + esac + + if [ "$IGNORE_DSCP_INGRESS" = "1" ]; then + sqm_debug "Do not perform DSCP based filtering on ingress. (1-tier classification)" + $TC qdisc add dev $DEV root handle 1: `get_stab_string` htb default 10 + $TC class add dev $DEV parent 1: classid 1:1 htb $LQ rate ${DOWNLINK}kbit ceil ${DOWNLINK}kbit $BURST `get_htb_adsll_string` + $TC class add dev $DEV parent 1:1 classid 1:10 htb $LQ rate ${DOWNLINK}kbit ceil ${DOWNLINK}kbit $BURST prio 0 `get_htb_adsll_string` + $TC qdisc add dev $DEV parent 1:10 handle 110: $QDISC \ + `get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_flows ${DOWNLINK}` ${IQDISC_OPTS} + else + sqm_debug "Perform DSCP based filtering on ingress. (3-tier classification)" + $TC qdisc add dev $DEV root handle 1: `get_stab_string` htb default 12 + $TC class add dev $DEV parent 1: classid 1:1 htb $LQ rate ${CEIL}kbit ceil ${CEIL}kbit $BURST `get_htb_adsll_string` + $TC class add dev $DEV parent 1:1 classid 1:11 htb $LQ rate 32kbit ceil ${PRIO_RATE}kbit prio 1 `get_htb_adsll_string` + $TC class add dev $DEV parent 1:1 classid 1:12 htb $LQ rate ${BE_RATE}kbit ceil ${BE_CEIL}kbit $BURST prio 2 `get_htb_adsll_string` + $TC class add dev $DEV parent 1:1 classid 1:13 htb $LQ rate ${BK_RATE}kbit ceil ${BE_CEIL}kbit $BURST prio 3 `get_htb_adsll_string` + + $TC qdisc add dev $DEV parent 1:11 handle 110: $QDISC \ + `get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_quantum 500` `get_flows ${PRIO_RATE}` ${IQDISC_OPTS} + $TC qdisc add dev $DEV parent 1:12 handle 120: $QDISC \ + `get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_quantum 1500` `get_flows ${BE_RATE}` ${IQDISC_OPTS} + $TC qdisc add dev $DEV parent 1:13 handle 130: $QDISC \ + `get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_quantum 300` `get_flows ${BK_RATE}` ${IQDISC_OPTS} + + diffserv $DEV + fi + + $IP link set dev $DEV up + + # redirect all IP packets arriving in $IFACE to $DEV + + $TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \ + match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV + +} + +sqm_prepare_script() { + do_modules + verify_qdisc "htb" || return 1 + ipt_setup +} diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simple.qos.help b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simple.qos.help new file mode 100644 index 0000000..b3c0096 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simple.qos.help @@ -0,0 +1 @@ +BW-limited three-tier prioritisation scheme with your qdisc on each queue. (default) diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest.qos b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest.qos new file mode 100644 index 0000000..80fe208 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest.qos @@ -0,0 +1,104 @@ +################################################################################ +# simplest.qos (Cero3 Simple Shaper) +# +# Abstract: +# This is a single band fq_codel and ipv6 enabled shaping script for Ethernet +# gateways. This is nearly the simplest possible. With FQ_CODEL, the sparseness +# priority will work pretty well for a casual network. Flow-hashes should not +# overlap much with only a few users. +# +# References: +# This alternate shaper attempts to go for 1/u performance in a clever way +# http://git.coverfire.com/?p=linux-qos-scripts.git;a=blob;f=src-3tos.sh;hb=HEAD +# +################################################################################ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Copyright (C) 2012-2016 +# Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller +# +################################################################################ + +. ${SQM_LIB_DIR}/defaults.sh + +################################################################################ + +cake_egress() +{ + $TC qdisc add dev $IFACE root `get_stab_string` cake bandwidth ${UPLINK}kbit besteffort `get_cake_lla_string` ${EQDISC_OPTS} +} + +egress() { + + LQ="quantum `get_htb_quantum $IFACE ${UPLINK} ${ESHAPER_QUANTUM_DUR_US}`" + BURST="`get_htb_burst $IFACE ${UPLINK} ${ESHAPER_BURST_DUR_US}`" + + SILENT=1 $TC qdisc del dev $IFACE root + + case $QDISC in + cake*) cake_egress; return ;; + esac + + $TC qdisc add dev $IFACE root handle 1: `get_stab_string` htb default 10 + $TC class add dev $IFACE parent 1: classid 1:1 htb $LQ rate ${UPLINK}kbit ceil ${UPLINK}kbit $BURST `get_htb_adsll_string` + $TC class add dev $IFACE parent 1:1 classid 1:10 htb $LQ rate ${UPLINK}kbit ceil ${UPLINK}kbit $BURST prio 0 `get_htb_adsll_string` + $TC qdisc add dev $IFACE parent 1:10 handle 110: $QDISC \ + `get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_flows ${UPLINK}` ${EQDISC_OPTS} + +} + +cake_ingress() +{ + $TC qdisc add dev $DEV root `get_stab_string` cake bandwidth ${DOWNLINK}kbit besteffort `get_cake_lla_string` ${IQDISC_OPTS} + $IP link set dev $DEV up + + # redirect all IP packets arriving in $IFACE to $DEV + + $TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \ + match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV +} + +ingress() { + sqm_debug "ingress" + SILENT=1 $TC qdisc del dev $IFACE handle ffff: ingress + $TC qdisc add dev $IFACE handle ffff: ingress + + LQ="quantum `get_htb_quantum $IFACE ${DOWNLINK} ${ISHAPER_QUANTUM_DUR_US}`" + BURST="`get_htb_burst $IFACE ${DOWNLINK} ${ISHAPER_BURST_DUR_US}`" + + SILENT=1 $TC qdisc del dev $DEV root + + case $QDISC in + cake*) cake_ingress; return ;; + esac + + $TC qdisc add dev $DEV root handle 1: `get_stab_string` htb default 10 + $TC class add dev $DEV parent 1: classid 1:1 htb $LQ rate ${DOWNLINK}kbit ceil ${DOWNLINK}kbit $BURST `get_htb_adsll_string` + $TC class add dev $DEV parent 1:1 classid 1:10 htb $LQ rate ${DOWNLINK}kbit ceil ${DOWNLINK}kbit $BURST prio 0 `get_htb_adsll_string` + + # FIXME: I'd prefer to use a pre-nat filter but we need to detect if nat is on this interface + # AND we need to permute by a random number which we can't do from userspace filters + + # Most high rate flows are REALLY close. This stomps on those harder, but hurts on high rate long distance + #$TC qdisc add dev $DEV parent 1:10 handle 110: $QDISC limit $LIMIT $ECN interval 20ms target 3ms `get_flows ${DOWNLINK}` + $TC qdisc add dev $DEV parent 1:10 handle 110: $QDISC \ + `get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_flows ${DOWNLINK}` ${IQDISC_OPTS} + + $IP link set dev $DEV up + + # redirect all IP packets arriving in $IFACE to ifb0 + + $TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \ + match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV + +} + +sqm_prepare_script() { + do_modules + verify_qdisc "htb" || return 1 +} + +################################################################################ diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest.qos.help b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest.qos.help new file mode 100644 index 0000000..c359256 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest.qos.help @@ -0,0 +1 @@ +Simplest possible configuration: HTB rate limiter with your qdisc attached. diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest_tbf.qos b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest_tbf.qos new file mode 100644 index 0000000..3f7a1c3 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest_tbf.qos @@ -0,0 +1,85 @@ +################################################################################ +# simplest_tbf.qos (Simple TBF shaper) +# +# Abstract: +# This is a single band fq_codel and ipv6 enabled shaping script for Ethernet +# gateways. This is nearly the simplest possible. With FQ_CODEL, the sparseness +# priority will work pretty well for a casual network. Flow-hashes should not +# overlap much with only a few users. +# +# Uses TBF instead of HTB as that may give better performance on some +# architectures. +# +# References: +# This alternate shaper attempts to go for 1/u performance in a clever way +# http://git.coverfire.com/?p=linux-qos-scripts.git;a=blob;f=src-3tos.sh;hb=HEAD +# +################################################################################ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Copyright (C) 2012-2017 +# Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller +# +################################################################################ + +. ${SQM_LIB_DIR}/defaults.sh + +################################################################################ + +egress() { + + MTU=$(get_mtu $IFACE) + BURST="$(get_burst ${MTU:-1514} ${UPLINK} ${ESHAPER_BURST_DUR_US})" + BURST=${BURST:-1514} + + SILENT=1 $TC qdisc del dev $IFACE root + + $TC qdisc add dev $IFACE root handle 1: $(get_stab_string) tbf \ + rate ${UPLINK}kbit burst $BURST latency 300ms $(get_htb_adsll_string) + $TC qdisc add dev $IFACE parent 1: handle 110: $QDISC \ + $(get_limit ${ELIMIT}) $(get_target "${ETARGET}" ${UPLINK}) \ + $(get_ecn ${EECN}) $(get_flows ${UPLINK}) ${EQDISC_OPTS} + +} + +ingress() { + sqm_debug "ingress" + SILENT=1 $TC qdisc del dev $IFACE handle ffff: ingress + $TC qdisc add dev $IFACE handle ffff: ingress + + MTU=$(get_mtu $IFACE) + BURST="$(get_burst ${MTU:-1514} ${DOWNLINK} ${ISHAPER_BURST_DUR_US})" + BURST=${BURST:-1514} + + SILENT=1 $TC qdisc del dev $DEV root + + $TC qdisc add dev $DEV root handle 1: $(get_stab_string) tbf \ + rate ${DOWNLINK}kbit burst $BURST latency 300ms $(get_htb_adsll_string) + $TC qdisc add dev $DEV parent 1: handle 110: $QDISC \ + $(get_limit ${ILIMIT}) $(get_target "${ITARGET}" ${DOWNLINK}) \ + $(get_ecn ${IECN}) $(get_flows ${DOWNLINK}) ${IQDISC_OPTS} + + $IP link set dev $DEV up + + # redirect all IP packets arriving in $IFACE to ifb0 + + $TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \ + match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV + +} + +sqm_prepare_script() { + do_modules + verify_qdisc "tbf" || return 1 + + case $QDISC in + cake*) + sqm_warn "Cake is not supported with this script; falling back to FQ-CoDel" + QDISC=fq_codel ;; + esac +} + +################################################################################ diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest_tbf.qos.help b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest_tbf.qos.help new file mode 100644 index 0000000..3f93f89 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/simplest_tbf.qos.help @@ -0,0 +1,2 @@ +Simplest possible configuration (TBF): TBF rate limiter with your qdisc attached. +TBF may give better performance than HTB on some architectures. diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/start-sqm b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/start-sqm new file mode 100644 index 0000000..cd76e01 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/start-sqm @@ -0,0 +1,66 @@ +#!/bin/sh + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Copyright (C) 2012-4 Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller + + +[ -n "$IFACE" ] || exit 1 + +. /etc/sqm/sqm.conf +. ${SQM_LIB_DIR}/functions.sh +. ${SQM_LIB_DIR}/defaults.sh +STATE_FILE="${SQM_STATE_DIR}/${IFACE}.state" + +check_state_dir + +# log file for the most recent sqm instance start +if [ "$SQM_DEBUG" -eq "1" ] ; then + SQM_DEBUG_LOG="${SQM_START_LOG}" + OUTPUT_TARGET="${SQM_DEBUG_LOG}" + echo "start-sqm: Log for interface ${IFACE}: $(date)" > "${OUTPUT_TARGET}" +fi + +if [ -z "${SCRIPT}" ] ; then + sqm_error "SCRIPT value is not defined in /etc/sqm/${IFACE}.iface.conf" + sqm_error "Please check your configuration and try again." + exit 1 +fi + +if [ -f "${STATE_FILE}" ]; then + sqm_error "SQM already activated on ${IFACE}." + exit 1 +fi + +# in case of spurious hotplug events, try double check whether the interface is really up +if [ ! -d /sys/class/net/${IFACE} ] ; then + sqm_error "${IFACE} does currently not exist, not even trying to start SQM on nothing." + exit 1 +fi + +if [ "${ENABLED:-1}" -ne "1" ]; then + sqm_log "SQM config disabled on ${IFACE}." + exit 0 +fi + +if [ ! -f "${SQM_LIB_DIR}/$SCRIPT" ]; then + sqm_error "SQM script ${SCRIPT} not found!" + exit 1 +fi + +. "${SQM_LIB_DIR}/$SCRIPT" + +sqm_trace; sqm_trace "$(date): Starting." # Add some space and a date stamp to verbose log output and log files to separate runs +sqm_log "Starting SQM script: ${SCRIPT} on ${IFACE}, in: ${DOWNLINK} Kbps, out: ${UPLINK} Kbps" + +if fn_exists sqm_start ; then + sqm_debug "Using script specific sqm_start function overriding the generic sqm_start_default." + sqm_start && write_state_file ${STATE_FILE} && sqm_log "${SCRIPT} was started on ${IFACE} successfully" +else + sqm_debug "Using generic sqm_start_default function." + sqm_start_default && write_state_file ${STATE_FILE} && sqm_log "${SCRIPT} was started on ${IFACE} successfully" +fi + +exit 0 diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/stop-sqm b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/stop-sqm new file mode 100644 index 0000000..9a9cbeb --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/stop-sqm @@ -0,0 +1,54 @@ +#!/bin/sh + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Copyright (C) 2012-4 Michael D. Taht, Toke Høiland-Jørgensen, Sebastian Moeller + +# allow passing in the IFACE as first command line argument + +[ -n "$IFACE" ] || exit 1 + +. /etc/sqm/sqm.conf +. ${SQM_LIB_DIR}/functions.sh +. ${SQM_LIB_DIR}/defaults.sh + +check_state_dir +# log file for the most recent sqm instance stop +if [ "$SQM_DEBUG" -eq "1" ] ; then + SQM_DEBUG_LOG="${SQM_STOP_LOG}" + OUTPUT_TARGET="${SQM_DEBUG_LOG}" + echo "stop-sqm: Log for interface ${IFACE}: $(date)" > "${OUTPUT_TARGET}" +fi + +if [ ! -f "${SQM_STATE_DIR}/${IFACE}.state" ] ; then + sqm_error "State file does not exist; SQM was not running on interface ${IFACE}" + exit 1 +fi +STATE_FILE="${SQM_STATE_DIR}/${IFACE}.state" + +if [ -z "${SCRIPT}" ] ; then + sqm_error "SCRIPT value is not defined in /etc/sqm/${IFACE}.iface.conf" + sqm_error "Please check your configuration and try again." + exit 1 +fi + +sqm_trace; sqm_trace "$(date): Stopping." # Add some space and a date stamp to verbose log output and log files to separate runs +sqm_log "Stopping SQM on ${IFACE}" + +# make sure to only delete the ifb associated with the current interface +CUR_IFB=$( get_ifb_associated_with_if ${IFACE} ) +[ -z "$CUR_IFB" ] && CUR_IFB=$( ifb_name ${IFACE} ) + +if [ ! -f "${SQM_LIB_DIR}/$SCRIPT" ]; then + sqm_error "SQM script ${SCRIPT} not found!" + exit 1 +fi + +. "${SQM_LIB_DIR}/$SCRIPT" + +sqm_stop +rm -f "${STATE_FILE}" + +exit 0 diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/update-available-qdiscs b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/update-available-qdiscs new file mode 100644 index 0000000..c966a19 --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/sqm/update-available-qdiscs @@ -0,0 +1,14 @@ +#!/bin/sh + +. /etc/sqm/sqm.conf +. ${SQM_LIB_DIR}/functions.sh +. ${SQM_LIB_DIR}/defaults.sh + +[ -d "${SQM_QDISC_STATE_DIR}" ] || mkdir -p "${SQM_QDISC_STATE_DIR}" + +SQM_VERBOSITY_MIN=5 # Silence errors while checking + +for qdisc in $SQM_CHECK_QDISCS; do + [ -f ${SQM_QDISC_STATE_DIR}/$qdisc ] && continue + verify_qdisc $qdisc && touch ${SQM_QDISC_STATE_DIR}/$qdisc +done diff --git a/rooter/0optionalapps/ext-throttle/files/usr/lib/throttle/throttle.sh b/rooter/0optionalapps/ext-throttle/files/usr/lib/throttle/throttle.sh new file mode 100644 index 0000000..6178cdb --- /dev/null +++ b/rooter/0optionalapps/ext-throttle/files/usr/lib/throttle/throttle.sh @@ -0,0 +1,47 @@ +#!/bin/sh +. /lib/functions.sh + +stop_interface() { + INTER=$1 + DEVICE=$(uci -q get sqm.$INTER.interface) + uci set sqm.$INTER.enabled='0' + uci commit sqm + if [ $DEVICE != "0" ]; then + /usr/lib/sqm/run.sh stop ${DEVICE} + fi +} + +start_interface() { + INTER=$1 + sdown=$2 + sup=$3 + uci set sqm.$INTER.enabled='1' + uci set sqm.$INTER.download=$sdown + uci set sqm.$INTER.upload=$sup + uci commit sqm + DEVICE=$(uci -q get sqm.$INTER.interface) + if [ $DEVICE != "0" ]; then + /usr/lib/sqm/run.sh stop ${DEVICE} + /usr/lib/sqm/run.sh start ${DEVICE} + fi +} + +cmd=$1 +if [ $cmd = 'start' ]; then + mult=$4 + if [ -z $mult ]; then + down=$2"000" + up=$3"000" + else + down=$2 + up=$3 + fi + /etc/init.d/sqm enabled + start_interface wan $down $up + start_interface wan1 $down $up + start_interface wan2 $down $up +else + stop_interface wan + stop_interface wan1 + stop_interface wan2 +fi \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/Makefile b/rooter/0optionalapps/ext-wireguard/Makefile new file mode 100644 index 0000000..e46e0df --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-wireguard +PKG_VERSION:=4.500 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-wireguard + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + DEPENDS:=+wireguard-tools +kmod-wireguard \ + +luci-proto-wireguard +udp-tunnel +eoip + TITLE:=Install scripts for Wireguard + PKGARCH:=all +endef + +define Package/ext-wireguard/description + Install scripts for Wireguard +endef + + +define Build/Compile +endef + +define Package/ext-wireguard/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,ext-wireguard)) diff --git a/rooter/0optionalapps/ext-wireguard/files/etc/config/wireguard b/rooter/0optionalapps/ext-wireguard/files/etc/config/wireguard new file mode 100644 index 0000000..77908d4 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/etc/config/wireguard @@ -0,0 +1,5 @@ + +config settings 'settings' + option enabled '0' + option client '0' + option server '0' diff --git a/rooter/0optionalapps/ext-wireguard/files/etc/config/wireguard_recipes b/rooter/0optionalapps/ext-wireguard/files/etc/config/wireguard_recipes new file mode 100644 index 0000000..52a6b2b --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/etc/config/wireguard_recipes @@ -0,0 +1,36 @@ +config wireguard_recipe b_client + option _description "Wireguard Client" + option _role "client" + option client "1" + option port "51280" + option auto '0' + option addresses '' + option dns '' + option privatekey '' + option name '' + option keepalive '25' + option publickey '' + option presharedkey '' + option ips '' + option ra_ips '1' + option endpoint_host '' + option sport '51280' + option active '0' + option udptunnel '0' + option mtu '1280' + +config wireguard_recipe b_server + option _description "Wireguard Server" + option _role "server" + option client "0" + option port "51280" + option auto '0' + option addresses '' + option publickey '' + option privatekey '' + option usepre '0' + option presharedkey '' + option active '0' + option udptunnel '0' + option udpport '54321' + option mtu '1280' \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/files/etc/init.d/wireguard b/rooter/0optionalapps/ext-wireguard/files/etc/init.d/wireguard new file mode 100644 index 0000000..4e49b81 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/etc/init.d/wireguard @@ -0,0 +1,87 @@ +#!/bin/sh /etc/rc.common +. /lib/functions.sh +# Copyright (C) 2006 OpenWrt.org + +START=99 + +log() { + logger -t "WireGuard Init.d : " "$@" +} + +chk_zone() { + local config=$1 + + config_get src $config src + config_get dest $config dest + if [ $src = "lan" -a $dest = "wg" ]; then + uci set firewall."$config".dest="wan" + uci commit firewall + fi +} + +check_config () { + log "Check Client Interfaces" + uci delete network.wg0 + uci delete network.wg1 + uci commit network + uci set network.wg0=interface + uci set network.wg0.proto="wireguard" + uci set network.wg0.auto="0" + uci set network.wg0.private_key="" + uci set network.wg0.listen_port="" + uci add_list network.wg0.addresses="" + uci set network.wg1=interface + uci set network.wg1.proto="wireguard" + uci set network.wg1.auto="0" + uci set network.wg1.private_key="" + uci set network.wg1.listen_port="" + uci add_list network.wg1.addresses="" + uci commit network + + uci delete firewall.wgzone + uci delete firewall.wgwforward + uci delete firewall.wwgforward + uci delete firewall.lwgforward + uci delete firewall.wglforward + uci commit firewall + uci set firewall.wgzone=zone + uci set firewall.wgzone.name="wg" + uci set firewall.wgzone.forward="ACCEPT" + uci set firewall.wgzone.output="ACCEPT" + uci set firewall.wgzone.network="wg0 wg1" + uci set firewall.wgzone.input="ACCEPT" + uci set firewall.wgzone.masq="1" + uci set firewall.wgzone.mtu_fix="1" + uci commit firewall + + config_load firewall + config_foreach chk_zone forwarding + + /etc/init.d/firewall restart +} + +chk_start() { + local config=$1 + + config_get auto $config auto + uci set wireguard."$config".active="0" + uci commit wireguard + if [ $auto = '1' ]; then + /usr/lib/wireguard/startvpn.sh $config + else + /usr/lib/wireguard/stopvpn.sh $config + fi +} + +start() { + uci set wireguard.settings.client="0" + uci set wireguard.settings.server="0" + uci commit wireguard + if [ ! -e /etc/openvpn ]; then + mkdir /etc/openvpn + fi + check_config + + config_load wireguard + config_foreach chk_start wireguard +} \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/controller/wireguard.lua b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/controller/wireguard.lua new file mode 100644 index 0000000..48ea3c3 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/controller/wireguard.lua @@ -0,0 +1,111 @@ +-- Copyright 2016-2017 Dan Luedtke +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.wireguard", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + entry({"admin", "vpn", "wireguard"}, cbi("wireguard"), _("Wireguard"), 63) + entry( {"admin", "vpn", "wireguard", "client"}, cbi("wireguard-client"), nil ).leaf = true + entry( {"admin", "vpn", "wireguard", "server"}, cbi("wireguard-server"), nil ).leaf = true + end + + entry( {"admin", "vpn", "wireguard", "wupload"}, call("conf_upload")) + entry( {"admin", "vpn", "generateconf"}, call("conf_gen")) + entry( {"admin", "vpn", "textconf"}, call("text_gen")) + entry( {"admin", "vpn", "wirestatus"}, call("wirestatus")) +end + +function conf_upload() + local fs = require("nixio.fs") + local http = require("luci.http") + local util = require("luci.util") + local uci = require("luci.model.uci").cursor() + local upload = http.formvalue("ovpn_file") + local name = http.formvalue("instance_name2") + local file = "/etc/openvpn/" ..name.. ".conf" + + if name and upload then + local fp + + http.setfilehandler( + function(meta, chunk, eof) + local data = util.trim(chunk:gsub("\r\n", "\n")) .. "\n" + data = util.trim(data:gsub("[\128-\255]", "")) + + if not fp and meta and meta.name == "ovpn_file" then + fp = io.open(file, "w") + end + if fp and data then + fp:write(data) + end + if fp and eof then + fp:close() + end + end + ) + + if fs.access(file) then + os.execute("/usr/lib/wireguard/conf.sh " .. name .. " " .. file) + end + end + http.redirect(luci.dispatcher.build_url('admin/vpn/wireguard')) +end + +function conf_gen() + os.execute("/usr/lib/wireguard/create.sh") +end + +function text_gen() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/wireguard/text.sh " .. "\"" .. set .. "\"") +end + +function wirestatus() + local data = { } + local last_device = "" + + local wg_dump = io.popen("wg show all dump") + if wg_dump then + local line + for line in wg_dump:lines() do + local line = string.split(line, "\t") + if not (last_device == line[1]) then + last_device = line[1] + data[line[1]] = { + name = line[1], + public_key = line[3], + listen_port = line[4], + fwmark = line[5], + peers = { } + } + else + local peer = { + public_key = line[2], + endpoint = line[4], + allowed_ips = { }, + latest_handshake = line[6], + transfer_rx = line[7], + transfer_tx = line[8], + persistent_keepalive = line[9] + } + if not (line[4] == '(none)') then + for ipkey, ipvalue in pairs(string.split(line[5], ",")) do + if #ipvalue > 0 then + table.insert(peer['allowed_ips'], ipvalue) + end + end + end + table.insert(data[line[1]].peers, peer) + end + end + end + + luci.http.prepare_content("application/json") + luci.http.write_json(data) +end \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard-client.lua b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard-client.lua new file mode 100644 index 0000000..ec041aa --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard-client.lua @@ -0,0 +1,99 @@ +require("luci.ip") +require("luci.model.uci") + +--luci.sys.call("/usr/lib/wireguard/keygen.sh " .. arg[1]) + +local m = Map("wireguard", translate("Wireguard Client"), translate("Set up a Wireguard Client")) + +e = m:section(NamedSection, "settings", "") + +m.on_init = function(self) + --luci.sys.call("/usr/lib/wireguard/keygen.sh " .. arg[1]) +end + +btn = e:option(Button, "_btn", translate(" ")) +btn.inputtitle = translate("Back to Main Page") +btn.inputstyle = "apply" +btn.redirect = luci.dispatcher.build_url( + "admin", "vpn", "wireguard" +) +function btn.write(self, section, value) + luci.http.redirect( self.redirect ) +end + + +local s = m:section( NamedSection, arg[1], "wireguard", translate("Client") ) + +ip = s:option(Value, "addresses", translate("IP Addresses :"), translate("Comma separated list of IP Addresses that server will accept from this client")); +ip.rmempty = true; +ip.optional=false; +ip.default="10.14.0.2/24"; + +port = s:option(Value, "port", translate("Listen Port :"), translate("Client Listen Port")); +port.rmempty = true; +port.optional=false; +port.default="51820"; + +ul = s:option(ListValue, "udptunnel", translate("Enable UDP over TCP :")); +ul:value("0", translate("No")) +ul:value("1", translate("Yes")) +ul.default=0 + +dns = s:option(Value, "dns", translate("DNS Servers :"), translate("Comma separated list of DNS Servers.")); +dns.rmempty = true; +dns.optional=false; + +mtu = s:option(Value, "mtu", translate("MTU :"), translate("Maximum MTU")); +mtu.rmempty = true; +mtu.optional=false; +mtu.datatype = 'range(1280,1420)'; +mtu.default="1280"; + +pka = s:option(Value, "persistent_keepalive", translate("Persistent Keep Alive :"), translate("Seconds between keep alive messages")); +pka.rmempty = true; +pka.optional=false; +pka.datatype = 'range(1,100)'; +pka.default="25"; + +pkey = s:option(Value, "privatekey", translate("Private Key :"), translate("Private Key supplied by the Server")); +pkey.rmempty = true; +pkey.optional=false; + +bl = s:option(ListValue, "auto", translate("Start on Boot :")); +bl:value("0", translate("No")) +bl:value("1", translate("Yes")) +bl.default="0" + +xbl = s:option(ListValue, "forward", translate("All Traffic Through Tunnel :")); +xbl:value("0", translate("No")) +xbl:value("1", translate("Yes")) +xbl.default="1" + +s = m:section( NamedSection, arg[1], "wireguard", translate("Server") ) + +name = s:option( Value, "name", translate("Server Name :"), translate("Optional Server name")) + +pukey = s:option(Value, "publickey", translate("Public Key :"), translate("Public Key of the Server")); +pukey.rmempty = true; +pukey.optional=false; + +prkey = s:option(Value, "presharedkey", translate("Presharedkey :"), translate("PreShared Key from the Server")); +prkey.rmempty = true; +prkey.optional=false; + +host = s:option(Value, "endpoint_host", translate("Server Address :"), translate("URL or IP Address of Server")); +host.rmempty = true; +host.optional=false; +host.default=""; + +sport = s:option(Value, "sport", translate("Listen Port :"), translate("Server Listen Port")); +sport.rmempty = true; +sport.optional=false; +sport.default="51820"; + +sip = s:option(Value, "ips", translate("Allowed IP Addresses :"), translate("Comma separated list of IP Addresses that server will accept")); +sip.rmempty = true; +sip.optional=false; +sip.default="10.14.0.0/24"; + +return m \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard-server.lua b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard-server.lua new file mode 100644 index 0000000..5fb15ee --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard-server.lua @@ -0,0 +1,130 @@ +require("luci.ip") +require("luci.model.uci") + +--luci.sys.call("/usr/lib/wireguard/keygen.sh " .. arg[1]) + +local m = Map("wireguard", translate("Wireguard Server"), translate("Set up a Wireguard Server")) + +e = m:section(NamedSection, "settings", "") + +m.on_init = function(self) + luci.sys.call("/usr/lib/wireguard/keygen.sh " .. arg[1]) +end + +m.on_after_save = function(self) + luci.sys.call("/usr/lib/wireguard/keygen.sh " .. arg[1] .. "&") +end + +btn = e:option(Button, "_btn", translate(" ")) +btn.inputtitle = translate("Back to Main Page") +btn.inputstyle = "apply" +btn.redirect = luci.dispatcher.build_url( + "admin", "vpn", "wireguard" +) +function btn.write(self, section, value) + luci.http.redirect( self.redirect ) +end + + +local s = m:section( NamedSection, arg[1], "wireguard", translate("Server") ) + +ip = s:option(Value, "addresses", translate("Internal IP Address :")); +ip.rmempty = true; +ip.optional=false; +ip.default="10.14.0.1/32"; +ip.datatype = "ipaddr" + +host = s:option(Value, "endpoint_host", translate("Server Address :"), translate("URL or IP Address of Server")); +host.rmempty = true; +host.optional=false; +host.default="example.wireguard.org"; + +port = s:option(Value, "port", translate("Port :"), translate("Server Listen Port. Default is 51280")); +port.rmempty = true; +port.optional=false; +port.default="51280"; + +ul = s:option(ListValue, "udptunnel", "Enable UDP over TCP :"); +ul:value("0", translate("No")) +ul:value("1", translate("Yes")) +ul.default=0 + +uport = s:option(Value, "udpport", translate("UDP over TCP Port :"), translate("Server Local TCP Port. Default is 54321")); +uport.rmempty = true; +uport.optional=false; +uport.default="54321"; +uport:depends("udptunnel", "1") + +pkey = s:option(DummyValue, "privatekey", translate("Private Key :")); +pkey.optional=false; + +pukey = s:option(DummyValue, "publickey", translate("Public Key :"), translate("Server Public key sent to Clients")); +pukey.optional=false; + +pl = s:option(ListValue, "usepre", "Use PreSharedKey :"); +pl:value("0", translate("No")) +pl:value("1", translate("Yes")) +pl.default=0 + +prkey = s:option(DummyValue, "presharedkey", translate("PreShared Key :"), translate("PreShared Key sent to Client")); +prkey.optional=false; +prkey:depends("usepre", "1") + +bl = s:option(ListValue, "auto", translate("Start on Boot :")); +bl:value("0", translate("No")) +bl:value("1", translate("Yes")) +bl.default="0" + +xbl = s:option(ListValue, "forward", translate("All Traffic Through Tunnel :")); +xbl:value("0", translate("No")) +xbl:value("1", translate("Yes")) +xbl.default="1" + + +b3 = s:option(DummyValue, "blank", " "); + +sx = s:option(Value, "_dmy1", translate(" ")) +sx.template = "wireguard/conf" + +ss = m:section(TypedSection, "custom" .. arg[1], translate("Clients"), translate("Clients of this server")) +ss.anonymous = true +ss.addremove = true + +name = ss:option(Value, "name", translate("Client Name")) +name.optional=false; + +cport = ss:option(Value, "endpoint_port", translate("Listen Port :"), translate("Port sent to Client. Default is 51280")); +cport.rmempty = true; +cport.optional=false; +cport.default=""; + +aip = ss:option(Value, "address", translate("Assigned IP Address :"), translate("IP Address assigned to Client")); +aip.rmempty = true; +aip.optional=false; +aip.default="10.14.0.2/32"; + +dns = ss:option(Value, "dns", translate("DNS Servers :"), translate("Comma separated list of DNS Servers sent to Client")); +dns.rmempty = true; +dns.optional=false; +dns.default=""; + +mtu = ss:option(Value, "mtu", translate("MTU :"), translate("Maximum MTU")); +mtu.rmempty = true; +mtu.optional=false; +mtu.datatype = 'range(1280,1420)'; +mtu.default="1280"; + +aip = ss:option(Value, "allowed_ips", translate("Allowed IP Address :"), translate("Comma separated list of IP Addresses allowed from Client")); +aip.rmempty = true; +aip.optional=false; +aip.default="0.0.0.0/0,::/0"; + +pukey = ss:option(DummyValue, "publickey", translate("Public Key :"), translate("Client Public Key")); +pukey.optional=false; + +pikey = ss:option(DummyValue, "privatekey", translate("Private Key :"), translate("Private Key sent to Client")); +pikey.optional=false; + +b3 = ss:option(DummyValue, "blank", " "); + +return m \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard.lua b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard.lua new file mode 100644 index 0000000..0aab305 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/model/cbi/wireguard.lua @@ -0,0 +1,182 @@ +local fs = require "nixio.fs" +local sys = require "luci.sys" +local uci = require "luci.model.uci".cursor() +local testfullps = sys.exec("ps --help 2>&1 | grep BusyBox") --check which ps do we have +local psstring = (string.len(testfullps)>0) and "ps w" or "ps axfw" --set command we use to get pid + +local m = Map("wireguard", translate("Wireguard"), translate("Set up a Wireguard VPN Tunnel on your Router")) + +local s = m:section( TypedSection, "wireguard", translate("Instances"), translate("Below is a list of configured Wireguard Instances and their current state") ) +s.template = "cbi/tblsection" +s.template_addremove = "wireguard/cbi-select-input-add" +s.addremove = true +s.add_select_options = { } + +local cfg = s:option(DummyValue, "config") +function cfg.cfgvalue(self, section) + local file_cfg = self.map:get(section, "client") + if file_cfg == "1" then + s.extedit = luci.dispatcher.build_url("admin", "vpn", "wireguard", "client", "%s") + else + s.extedit = luci.dispatcher.build_url("admin", "vpn", "wireguard", "server", "%s") + end +end + +uci:load("wireguard_recipes") +uci:foreach( "wireguard_recipes", "wireguard_recipe", + function(section) + s.add_select_options[section['.name']] = + section['_description'] or section['.name'] + end +) + +function s.parse(self, section) + local recipe = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".select" + ) + + if recipe and not s.add_select_options[recipe] then + self.invalid_cts = true + else + TypedSection.parse( self, section ) + end +end + +function s.create(self, name) + local recipe = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".select" + ) + local name = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".text" + ) + if #name > 3 and not name:match("[^a-zA-Z0-9_]") then + local s = uci:section("wireguard", "wireguard", name) + if s then + local options = uci:get_all("wireguard_recipes", recipe) + for k, v in pairs(options) do + if k ~= "_role" and k ~= "_description" then + if type(v) == "boolean" then + v = v and "1" or "0" + end + uci:set("wireguard", name, k, v) + end + end + uci:save("wireguard") + uci:commit("wireguard") + if extedit then + luci.http.redirect( self.extedit:format(name) ) + end + end + elseif #name > 0 then + self.invalid_cts = true + end + return 0 +end + +function s.remove(self, name) + local cfg_file = "/etc/openvpn/" ..name.. ".conf" + local auth_file = "/etc/openvpn/" ..name.. ".auth" + if fs.access(cfg_file) then + fs.unlink(cfg_file) + end + if fs.access(auth_file) then + fs.unlink(auth_file) + end + uci:delete("wireguard", name) + uci:save("wireguard") + uci:commit("wireguard") +end + +local port = s:option( DummyValue, "client", translate("Type") ) +function port.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if val == nil then + val = 0 + end + if val == "1" then + return "Client" + else + return "Server" + end +end + +local addr = s:option( DummyValue, "addresses", translate("IP Addresses") ) +function addr.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + return val or "----" +end + +local auto = s:option( DummyValue, "udptunnel", translate("UDP over TCP") ) +function auto.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if val == nil then + val = 0 + end + if val == "1" then + return "Yes" + else + return "No" + end +end + +local auto = s:option( DummyValue, "auto", translate("Start on Boot") ) +function auto.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if val == nil then + val = 0 + end + if val == "1" then + return "Yes" + else + return "No" + end +end + +local active = s:option( DummyValue, "active", translate("Started") ) +function active.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if val == nil then + val = 0 + end + if val == "1" then + return "Yes" + else + return "No" + end +end + +local updown = s:option( Button, "_updown", translate("Start/Stop") ) +updown._state = false +updown.redirect = luci.dispatcher.build_url( + "admin", "vpn", "wireguard" +) +function updown.cbid(self, section) + local file_cfg = self.map:get(section, "active") + if file_cfg == "1" then + pid = 1 + else + pid = nil + end + self._state = pid ~= nil + self.option = self._state and "stop" or "start" + return AbstractValue.cbid(self, section) +end +function updown.cfgvalue(self, section) + self.title = self._state and "stop" or "start" + self.inputstyle = self._state and "reset" or "reload" +end +function updown.write(self, section, value) + if self.option == "stop" then + sys.call("/usr/lib/wireguard/stopvpn.sh %s" % section) + else + sys.call("/usr/lib/wireguard/startvpn.sh %s" % section) + end + luci.http.redirect( self.redirect ) +end + +m:section(SimpleSection).template = "wireguard/wireguard" + +return m \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/cbi-select-input-add.htm b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/cbi-select-input-add.htm new file mode 100644 index 0000000..c6cb8ac --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/cbi-select-input-add.htm @@ -0,0 +1,111 @@ + + + +<%+wireguard/ovpn_css%> + +
                +
                +

                <%:Template based configuration%>

                +
                +
                + +
                +
                + +
                +
                +
                +
                +
                +

                <%:Conf configuration file upload%>

                +
                +
                + +
                +
                + +
                +
                + +
                +
                +
                +
                + +
                +
                diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/conf.htm b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/conf.htm new file mode 100644 index 0000000..e75e88f --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/conf.htm @@ -0,0 +1,27 @@ + + + +
                + + + + + + + +
                   
                +
                diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/ovpn_css.htm b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/ovpn_css.htm new file mode 100644 index 0000000..55c0a54 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/ovpn_css.htm @@ -0,0 +1,38 @@ + diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/pageswitch.htm b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/pageswitch.htm new file mode 100644 index 0000000..47056fa --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/pageswitch.htm @@ -0,0 +1,30 @@ +<%# + Copyright 2008 Steven Barth + Copyright 2008 Jo-Philipp Wich + Licensed to the public under the Apache License 2.0. +-%> + +<%+openvpn/ovpn_css%> + +
                +

                + <%:Overview%> » + <%=luci.i18n.translatef("Instance \"%s\"", self.instance)%> +

                + <% if self.mode == "basic" then %> + "><%:Switch to advanced configuration%> »

                +


                + <% elseif self.mode == "advanced" then %> + <%:Switch to basic configuration%> »

                +


                + <%:Configuration category%>: + <% for i, c in ipairs(self.categories) do %> + <% if c == self.category then %> + <%=translate(c)%> + <% else %> + "><%=translate(c)%> + <% end %> + <% if next(self.categories, i) then %>|<% end %> + <% end %> + <% end %> +
                diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/text_conf.htm b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/text_conf.htm new file mode 100644 index 0000000..2a1a4b5 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/text_conf.htm @@ -0,0 +1,61 @@ +<% + +%> + + + +
                + <%:Paste Configuration File Here%> + + + + +
                + +
                + + + + + + + + + + +
                <%:Instance Name : %>
                <%:Start on Boot : %>
                + +  
                +
                diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/wireguard.htm b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/wireguard.htm new file mode 100644 index 0000000..d207f05 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/lua/luci/view/wireguard/wireguard.htm @@ -0,0 +1,153 @@ +<%# + Copyright 2016-2017 Dan Luedtke + Licensed to the public under the Apache License 2.0. +-%> + +<% + +-%> + + + +

                <%:WireGuard Status%>

                + +
                + + <%:Interface%> WG0 + +
                + + + + + + + + + + + + + + + +
                  +
                <%:Configuration%>
                +
                   +
                + <%:Collecting data...%> +
                +
                  +
                <%:Peer%>
                +
                   +
                + <%:Collecting data...%> +
                +
                +
                + +
                + diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/conf.sh b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/conf.sh new file mode 100644 index 0000000..436e1f5 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/conf.sh @@ -0,0 +1,118 @@ +#!/bin/sh + +name=$1 +file=$2 +auto=$3 +if [ -z $auto ]; then + auto="0" +fi + +extract() { + line=$1 + PD=$(echo "$line" | grep "#") + if [ ! -z "$PD" ]; then + return + fi + PRK=$(echo "$line" | grep "PrivateKey" | tr " " ",") + if [ ! -z "$PRK" ]; then + PrivateKey=$(echo $PRK | cut -d, -f3) + fi + PRK=$(echo "$line" | grep "PublicKey" | tr " " ",") + if [ ! -z "$PRK" ]; then + PublicKey=$(echo $PRK | cut -d, -f3) + fi + PRK=$(echo "$line" | grep "PresharedKey" | tr " " ",") + if [ ! -z "$PRK" ]; then + PreSharedKey=$(echo $PRK | cut -d, -f3) + fi + PRK=$(echo "$line" | grep "Address" | tr " " "#") + if [ ! -z "$PRK" ]; then + if [ -z $Address ]; then + Address=$(echo $PRK | cut -d# -f3) + else + Address=$Address","$(echo $PRK | cut -d# -f3) + fi + fi + PRK=$(echo "$line" | grep "dns" | tr " " "#") + if [ ! -z "$PRK" ]; then + dns=$(echo $PRK | cut -d# -f3) + fi + PRK=$(echo "$line" | grep "DNS" | tr " " "#") + if [ ! -z "$PRK" ]; then + dns=$(echo $PRK | cut -d# -f3) + fi + PRK=$(echo "$line" | grep "ListenPort" | tr " " ",") + if [ ! -z "$PRK" ]; then + listenport=$(echo $PRK | cut -d, -f3) + fi + PRK=$(echo "$line" | grep "AllowedIPs" | tr " " "#") + if [ ! -z "$PRK" ]; then + if [ -z $allowedips ]; then + allowedips=$(echo $PRK | cut -d# -f3) + else + allowedips=$allowedips","$(echo $PRK | cut -d# -f3) + fi + fi + PRK=$(echo "$line" | grep "Endpoint" | tr " " ",") + if [ ! -z "$PRK" ]; then + endpoint=$(echo $PRK | cut -d, -f3) + fi + MTU=$(echo "$line" | grep "MTU" | tr " " ",") + if [ ! -z "$MTU" ]; then + mtu=$(echo $MTU | cut -d, -f3) + fi +} + +listenport="51280" +dns="" +sed -i -e "s!PrivateKey= !PrivateKey=!g" $file +sed -i -e "s!PrivateKey=!PrivateKey = !g" $file +sed -i -e "s!PublicKey= !PublicKey=!g" $file +sed -i -e "s!PublicKey=!PublicKey = !g" $file +sed -i -e "s!PresharedKey= !PresharedKey=!g" $file +sed -i -e "s!PresharedKey=!PresharedKey = !g" $file +sed -i -e "s!Address= !Address=!g" $file +sed -i -e "s!Address=!Address = !g" $file +sed -i -e "s!dns= !dns=!g" $file +sed -i -e "s!dns=!dns = !g" $file +sed -i -e "s!DNS= !DNS=!g" $file +sed -i -e "s!DNS=!DNS = !g" $file +sed -i -e "s!ListenPort= !ListenPort=!g" $file +sed -i -e "s!ListenPort=!ListenPort = !g" $file +sed -i -e "s!AllowedIPs= !AllowedIPs=!g" $file +sed -i -e "s!AllowedIPs=!AllowedIPs = !g" $file +sed -i -e "s!Endpoint= !Endpoint=!g" $file +sed -i -e "s!Endpoint=!Endpoint = !g" $file +sed -i -e "s!MTU= !MTU=!g" $file +sed -i -e "s!MTU=!MTU = !g" $file + +while IFS= read -r linex +do + extract "$linex" +done < $file +extract "$linex" +PRK=$(echo "$endpoint" | tr ":" ",") +endpoint=$(echo $PRK | cut -d, -f1) +sport=$(echo $PRK | cut -d, -f2) + +uci delete wireguard.$name +uci set wireguard.$name=wireguard +uci set wireguard.$name.auto=$auto +uci set wireguard.$name.client="1" +uci set wireguard.$name.active="0" +uci set wireguard.$name.privatekey="$PrivateKey" +uci set wireguard.$name.presharedkey="$PreSharedKey" +uci set wireguard.$name.port="$listenport" +uci set wireguard.$name.addresses="$Address" +uci set wireguard.$name.dns="$dns" +uci set wireguard.$name.publickey="$PublicKey" +uci set wireguard.$name.endpoint_host="$endpoint" +uci set wireguard.$name.ips="$allowedips" +uci set wireguard.$name.name="$name" +uci set wireguard.$name.sport="$sport" +uci set wireguard.$name.mtu="$mtu" +uci set wireguard.$name.persistent_keepalive='25' +uci commit wireguard + +rm -f $file + \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/create.sh b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/create.sh new file mode 100644 index 0000000..9d41829 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/create.sh @@ -0,0 +1,76 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Wireguard Conf" "$@" +} + +WG=$(cat /tmp/wginst) + +do_create() { + local config=$1 + + config_get name $config name + if [ -z $name ]; then + name=$config + fi + + echo "----Start Conf File for "$name" ----" >> ${PKI_DIR}/package/wg.conf + echo "[Interface]" >> ${PKI_DIR}/package/wg.conf + config_get privatekey $config privatekey + echo "PrivateKey = "$privatekey >> ${PKI_DIR}/package/wg.conf + config_get address $config address + echo "Address = "$address >> ${PKI_DIR}/package/wg.conf + config_get endpoint_port $config endpoint_port + if [ ! -z $endpoint_port ]; then + echo "ListenPort = "$endpoint_port >> ${PKI_DIR}/package/wg.conf + fi + config_get dns $config dns + if [ ! -z $dns ]; then + echo "DNS = "$dns >> ${PKI_DIR}/package/wg.conf + fi + config_get mtu $config mtu + if [ ! -z $mtu ]; then + echo "MTU = "$mtu >> ${PKI_DIR}/package/wg.conf + fi + echo " " >> ${PKI_DIR}/package/wg.conf + echo "[Peer]" >> ${PKI_DIR}/package/wg.conf + PUB=$(uci get wireguard."$WG".publickey) + echo "PublicKey = "$PUB >> ${PKI_DIR}/package/wg.conf + USE=$(uci get wireguard."$WG".usepre) + if [ $USE = "1" ]; then + PRE=$(uci get wireguard."$WG".presharedkey) + echo "PresharedKey = "$PRE >> ${PKI_DIR}/package/wg.conf + fi + HOST=$(uci get wireguard."$WG".endpoint_host) + PORT=$(uci get wireguard."$WG".port) + if [ ! -z $PORT ]; then + HOST=$HOST":"$PORT + fi + echo "Endpoint = "$HOST >> ${PKI_DIR}/package/wg.conf + config_get allowed_ips $config allowed_ips + echo "AllowedIPs = "$allowed_ips >> ${PKI_DIR}/package/wg.conf + echo "----EndConf File for "$name" ----" >> ${PKI_DIR}/package/wg.conf + echo " " >> ${PKI_DIR}/package/wg.conf +} + +#PKI_DIR="/tmp/wireguard" +PKI_DIR="/www" +#rm -rfv "$PKI_DIR" +#mkdir -p ${PKI_DIR} +#chmod -R 0777 ${PKI_DIR} +cd ${PKI_DIR} +mkdir -p package +cd .. +chmod -R 0777 ${PKI_DIR}/package +#rm -rfv "/www/package" +#ln -s ${PKI_DIR}/package /www/package + + +rm -f ${PKI_DIR}/package/wg.conf +config_load wireguard +config_foreach do_create custom$WG + +cd ${PKI_DIR}/package + +tar -czf wgconf.tar.gz wg.conf diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/keygen.sh b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/keygen.sh new file mode 100644 index 0000000..3b30f61 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/keygen.sh @@ -0,0 +1,63 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Wireguard KeyGen" "$@" +} + +WG=$1 +echo "$WG" > /tmp/wginst + +sleep 5 + +EXST=$(uci get wireguard."$WG") +if [ -z $EXST ]; then + uci set wireguard."$WG"="wireguard" + uci commit wireguard +fi + +PRIV=$(uci get wireguard."$WG".privatekey) +if [ -z $PRIV ]; then + umask u=rw,g=,o= + wg genkey | tee /tmp/wgserver.key | wg pubkey > /tmp/wgclient.pub + wg genpsk > /tmp/wg.psk + + WG_KEY="$(cat /tmp/wgserver.key)" # private key + WG_PSK="$(cat /tmp/wg.psk)" # shared key + WG_PUB="$(cat /tmp/wgclient.pub)" # public key to be used on other end + rm -f /tmp/wgserver.key + rm -f /tmp/wg.psk + rm -f /tmp/wgclient.pub + uci set wireguard."$WG".privatekey=$WG_KEY + uci set wireguard."$WG".publickey=$WG_PUB + uci set wireguard."$WG".presharedkey=$WG_PSK + uci commit wireguard +fi + +do_custom() { + local config=$1 + + config_get privatekey $config privatekey + if [ -z "$privatekey" ]; then + umask u=rw,g=,o= + wg genkey | tee /tmp/wgserver.key | wg pubkey > /tmp/wgclient.pub + wg genpsk > /tmp/wg.psk + + WG_KEY="$(cat /tmp/wgserver.key)" # private key + WG_PSK="$(cat /tmp/wg.psk)" # shared key + WG_PUB="$(cat /tmp/wgclient.pub)" # public key to be used on other end + rm -f /tmp/wgserver.key + rm -f /tmp/wg.psk + rm -f /tmp/wgclient.pub + log "$WG_KEY" + uci set wireguard."$config".privatekey=$WG_KEY + uci set wireguard."$config".publickey=$WG_PUB + uci set wireguard."$config".presharedkey=$WG_PSK + uci set wireguard."$config".persistent_keepalive='25' + uci set wireguard."$config".route_allowed_ips='1' + fi +} + +config_load wireguard +config_foreach do_custom custom$WG +uci commit wireguard \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/startvpn.sh b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/startvpn.sh new file mode 100644 index 0000000..352032d --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/startvpn.sh @@ -0,0 +1,318 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Wireguard Start" "$@" +} + +WG=$1 + +chk_zone() { + local config=$1 + + config_get src $config src + config_get dest $config dest + if [ $src = "lan" -a $dest = "wan" ]; then + uci set firewall."$config".dest="wg" + uci commit firewall + fi +} + +do_dns() { + cdns=$1 + ldns=$(uci -q get network.wg0.dns) + ex=$(echo "$ldns" | grep "$cdns") + if [ -z $ex ]; then + log "Add DNS $cdns to WG0" + uci add_list network.wg0.dns="$cdns" + uci commit network + /etc/init.d/network reload + fi +} + +do_port() { + PORT=$1 + udp=$2 + # look for rule for this port + INB="inbound"$PORT$udp + RULE=$(uci -q get firewall.$INB) + if [ -z $RULE ]; then + uci set firewall.$INB=rule + uci set firewall.$INB.name=$INB + uci set firewall.$INB.target=ACCEPT + uci set firewall.$INB.src=* + uci set firewall.$INB.proto=$udp + uci set firewall.$INB.dest_port=$PORT + uci commit firewall + /etc/init.d/firewall reload + fi +} + +do_delete() { + local config=$1 + + uci delete network.$1 +} + +create_speer() { + local config=$1 + + uci set network.$config="wireguard_wg1" + + config_get persistent_keepalive $config persistent_keepalive + uci set network.$config.persistent_keepalive="$persistent_keepalive" + config_get route_allowed_ips $config route_allowed_ips + uci set network.$config.route_allowed_ips="$route_allowed_ips" + config_get publickey $config publickey + uci set network.$config.public_key="$publickey" + usepre=$(uci -q get wireguard.$WG.usepre) + log "$usepre" + if [ $usepre = "1" ]; then + presharedkey=$(uci -q get wireguard.$WG.presharedkey) + log "$presharedkey" + uci set network.$config.preshared_key="$presharedkey" + fi + config_get allowed_ips $config allowed_ips + allowed_ips=$allowed_ips"," + ips=$(echo $allowed_ips | cut -d, -f1) + i=1 + while [ ! -z $ips ] + do + uci add_list network.$config.allowed_ips="$ips" + i=$((i+1)) + ips=$(echo $allowed_ips | cut -d, -f$i) + done + +} + +create_cpeer() { + local config=$1 + + uci set network.$config="wireguard_wg0" + + publickey=$(uci -q get wireguard."$config".publickey) + uci set network.$config.public_key="$publickey" + presharedkey=$(uci -q get wireguard."$WG".presharedkey) + if [ ! -z $presharedkey ]; then + uci set network.$config.preshared_key="$presharedkey" + fi + persistent_keepalive=$(uci -q get wireguard."$config".persistent_keepalive) + if [ -z $persistent_keepalive ]; then + persistent_keepalive=25 + fi + uci set network.$config.persistent_keepalive="$persistent_keepalive" + route_allowed_ips=1 + uci set network.$config.route_allowed_ips="$route_allowed_ips" + + if [ $UDP = 1 ]; then + endpoint_host="127.0.0.1" + uci set network.$config.endpoint_host="$endpoint_host" + sport=$(uci -q get wireguard."$config".port) + if [ -z $sport ]; then + sport="54321" + fi + uci set network.$config.endpoint_port="$sport" + else + endpoint_host=$(uci -q get wireguard."$config".endpoint_host) + uci set network.$config.endpoint_host="$endpoint_host" + sport=$(uci -q get wireguard."$config".sport) + if [ -z $sport ]; then + sport="51280" + fi + uci set network.$config.endpoint_port="$sport" + fi + + ips=$(uci -q get wireguard."$config".ips)"," + cips=$(echo $ips | cut -d, -f1) + i=1 + while [ ! -z $cips ] + do + uci add_list network.$config.allowed_ips="$cips" + i=$((i+1)) + cips=$(echo $ips | cut -d, -f$i) + done +} + +handle_server() { + config_foreach do_delete wireguard_wg1 + + uci delete network.wg1 + uci set network.wg1="interface" + uci set network.wg1.proto="wireguard" + + auto=$(uci -q get wireguard."$WG".auto) + if [ -z $auto ]; then + auto="0" + fi + uci set network.wg1.auto="$auto" + + port=$(uci -q get wireguard."$WG".port) + if [ -z $port ]; then + port="51280" + fi + uci set network.wg1.listen_port="$port" + do_port $port udp + + privatekey=$(uci -q get wireguard."$WG".privatekey) + uci set network.wg1.private_key="$privatekey" + + ips=$(uci -q get wireguard."$WG".addresses)"," + cips=$(echo $ips | cut -d, -f1) + i=1 + while [ ! -z $cips ] + do + uci add_list network.wg1.addresses="$cips" + i=$((i+1)) + cips=$(echo $ips | cut -d, -f"$i") + if [ -z $cips ]; then + break + fi + done + + config_load wireguard + config_foreach create_speer custom$WG + + uci commit network +} + +handle_client() { + config_foreach do_delete wireguard_wg0 + + uci delete network.wg0 + uci set network.wg0="interface" + uci set network.wg0.proto="wireguard" + + auto=$(uci -q get wireguard."$WG".auto) + if [ -z $auto ]; then + auto="0" + fi + uci set network.wg0.auto="$auto" + mtu=$(uci -q get wireguard."$WG".mtu) + if [ ! -z $mtu ]; then + uci set network.wg0.mtu="$mtu" + fi + dns=$(uci -q get wireguard."$WG".dns) + if [ ! -z $dns ]; then + do_dns $dns + fi + port=$(uci -q get wireguard."$WG".port) + if [ -z $port ]; then + port="51280" + fi + uci set network.wg0.listen_port="$port" + do_port $port udp + + privatekey=$(uci -q get wireguard."$WG".privatekey) + uci set network.wg0.private_key="$privatekey" + + ips=$(uci -q get wireguard."$WG".addresses)"," + cips=$(echo $ips | cut -d, -f1) + i=1 + while [ ! -z "$cips" ] + do + uci add_list network.wg0.addresses="$cips" + i=$((i+1)) + cips=$(echo "$ips" | cut -d, -f"$i") + if [ -z "$cips" ]; then + break + fi + done + uci add_list network.wg0.addresses="::/0" + + create_cpeer $WG + + uci commit network +} + +udp_server() { + local config=$1 + udpport=$(uci -q get wireguard."$WG".udpport) + if [ -z $udpport ]; then + udpport="54321" + fi + port=$(uci -q get wireguard."$WG".port) + if [ -z $port ]; then + port="54321" + fi + do_port $udpport tcp + udptunnel -s -v "0.0.0.0:"$udpport "127.0.0.1:"$port & + #log "udptunnel -s -v 0.0.0.0:$udpport 127.0.0.1:$port" +} + +udp_client() { + local config=$1 + port=$(uci -q get wireguard."$WG".port) + if [ -z $port ]; then + port="54321" + fi + endpoint_host=$(uci -q get wireguard.$WG.endpoint_host) + sport=$(uci -q get wireguard.$WG.sport) + if [ -z $sport ]; then + sport="51280" + fi + + udptunnel "127.0.0.1:"$port $endpoint_host":"$sport & + #log "udptunnel 127.0.0.1:$port $endpoint_host:$sport" +} + +forward=$(uci -q get wireguard."$WG".forward) +if [ "$forward" != "0" ]; then + config_load firewall + config_foreach chk_zone forwarding +else + uci set firewall.wgwforward=forwarding + uci set firewall.wgwforward.dest="wan" + uci set firewall.wgwforward.src="wg" + + uci set firewall.wwgforward=forwarding + uci set firewall.wwgforward.dest="wg" + uci set firewall.wwgforward.src="wan" + + uci set firewall.lwgforward=forwarding + uci set firewall.lwgforward.dest="wg" + uci set firewall.lwgforward.src="lan" + + uci set firewall.wglforward=forwarding + uci set firewall.wglforward.dest="lan" + uci set firewall.wglforward.src="wg" + uci commit firewall +fi +etc/init.d/firewall restart + +config_load network +SERVE=$(uci -q get wireguard."$WG".client) +if [ $SERVE = "0" ]; then + running=$(uci -q get wireguard.settings.server) + if [ $running = 1 ]; then + exit 0 + fi + UDP=$(uci -q get wireguard."$WG".udptunnel) + if [ $UDP = 1 ]; then + udp_server $WG + fi + handle_server + uci commit network + ifup wg1 + sleep 2 + uci set wireguard.settings.server="1" +else + running=$(uci -q get wireguard.settings.client) + log "Client running $running" + if [ $running = 1 ]; then + exit 0 + fi + UDP=$(uci -q get wireguard."$WG".udptunnel) + if [ $UDP = 1 ]; then + udp_client $WG + fi + handle_client + uci commit network + log "Start Interface" + ifup wg0 + sleep 2 + uci set wireguard.settings.client="1" +fi + +uci set wireguard."$WG".active="1" +uci commit wireguard + diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/stopvpn.sh b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/stopvpn.sh new file mode 100644 index 0000000..91e80dc --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/stopvpn.sh @@ -0,0 +1,67 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Wireguard Stop" "$@" +} + +chk_zone() { + local config=$1 + + config_get src $config src + config_get dest $config dest + if [ $src = "lan" -a $dest = "wg" ]; then + uci set firewall."$config".dest="wan" + uci commit firewall + fi +} + +WG=$1 + +forward=$(uci -q get wireguard."$WG".forward) +if [ "$forward" != "0" ]; then + config_load firewall + config_foreach chk_zone forwarding +else + uci delete firewall.wgwforward + uci delete firewall.wwgforward + uci delete firewall.lwgforward + uci delete firewall.wglforward + uci commit firewall +fi +/etc/init.d/firewall restart + +SERVE=$(uci get wireguard."$WG".client) +if [ $SERVE = "0" ]; then + ifdown wg1 + uci set wireguard.settings.server="0" + uci delete network.wg1 + uci set network.wg1=interface + uci set network.wg1.proto="wireguard" + uci set network.wg1.auto="0" + uci set network.wg1.private_key="" + uci set network.wg1.listen_port="" + uci add_list network.wg1.addresses="" + uci commit network +else + ifdown wg0 + uci set wireguard.settings.client="0" + uci delete network.wg0 + uci set network.wg0=interface + uci set network.wg0.proto="wireguard" + uci set network.wg0.auto="0" + uci set network.wg0.private_key="" + uci set network.wg0.listen_port="" + uci add_list network.wg0.addresses="" + uci commit network +fi +UDP=$(uci get wireguard."$WG".udptunnel) +if [ $UDP = 1 ]; then + PID=$(ps |grep "udptunnel" | grep -v grep |head -n 1 | awk '{print $1}') + kill -9 $PID +fi + +uci set wireguard."$WG".active="0" +uci commit wireguard + +/etc/init.d/wireguard stop \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/text.sh b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/text.sh new file mode 100644 index 0000000..2f5a622 --- /dev/null +++ b/rooter/0optionalapps/ext-wireguard/files/usr/lib/wireguard/text.sh @@ -0,0 +1,19 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Wireguard TextConf" "$@" +} + +conf1=$1 +conf=$(echo $conf1) +conf=$(echo "$conf" | tr "?" "~") + +boot=$(echo "$conf" | cut -d~ -f1) +iname=$(echo "$conf" | cut -d~ -f2) +conf=$(echo "$conf1" | tr "?" "~") +confile=$(echo "$conf" | cut -d~ -f3) + +echo "$confile" > /tmp/confile + +/usr/lib/wireguard/conf.sh $iname /tmp/confile $boot \ No newline at end of file diff --git a/rooter/0optionalapps/ext-wireguard/files/www/luci-static/resources/icons/wireguard.png b/rooter/0optionalapps/ext-wireguard/files/www/luci-static/resources/icons/wireguard.png new file mode 100644 index 0000000000000000000000000000000000000000..34f85d8486f4499a7ed215d5a20057f4048a9024 GIT binary patch literal 22762 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 YsyNG(0Rzr1YRU?j7+M$<>$@KPADp!95dZ)H literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/ext-wireguard/files/www/luci-static/resources/icons/wireguard_disabled.png b/rooter/0optionalapps/ext-wireguard/files/www/luci-static/resources/icons/wireguard_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..ccfb7aece3b8a4219681262fe78d78f2c477c6bc GIT binary patch literal 23205 zcmeI4c{r49|L`wl$riGts0j%fGsZe&$ujmeMz%_0W(v=#a&sh3FKg-ewUrC8mB(i`WQPB0YE`=<--)1xzis2IITSN^{uVl2_yp1 zo!|p9(bot0_z~PZ4&tcRJ*l>Ml1%-f zO&Hffz#0tf-+pZP2|!N$m=w$eIG@`p#FQQffY#$ENWfhKC}`asVE{Nl0YNvjdN}YL z3_wln-Hd_jWk5{}A6GHJ!3{unQBKMNYl4COjgpdqz=1g|sJfvhJS%Z!2wRCygD&U+$9n9ieOA~QWW<(tcfT1LdTv^;=Zt=2AF_nM=Tc+8c<|Fv&CheQFRNcmg~IlR z8m;;G^4{Ya^GvbUvujVd_6^4veJ8@G%`7A8kQ*$u6I`U z{)J>KHvZVWO}IFb=^%fwHxGX*u-jC`)av9?^ivcCslt> zk57*iOBVCnFI#Y2Pv%tfb#b}1si$&XuWjn@c7N`W3y1b0c8#i z#A!4Fu;ZUkRT?Rt3oYKI^_2UTetC}C#uJ8@x!SNK#pD>_^prNgn;W&FR5M1}^4-_< z#Axe3fYyv|U{|U?2vumP)4QQAzcwDzbVH(mJHKJ$_1y(572&g()*At91VRmJ)~c=v z&;y}2>l!L0Jf2!Z$3R67oU@R}$DG;+B z!WT@@uUC^22-k;gFOOw5xp5WMA<$vi;cX*1CZC(4Y`jr2{$UT+vzQ%zP9C(Q@#IkI zP~DKy(59iSQ_h^Jt~$O~Kia;Qv3YdBRP+ts8|61_xC<~{yDP~y{W%#Zew7#}y=xhz zHbuKm=d4#glnieU6E-o+ymtBgla1~o?sFbRqoh0h{pUAZCbrpkG>sXJCXTYq1aR}5 z5(;}j!OMuIY+&Dj7Y*1@biq7J^hu=X0~AzEas0wa(z+yqor7Gd+!3L;N1W$P&r6@* zBnLs|=4Iu*$m6n`wrfJgKK35~>bRIs3fZBQW zsN-Tdn`51Mot6I8UFkPm1}hstTo}=kK>4knJo%>%g{ss`-)QbW;xAWmVNtvyQY$Yv z1Fo-Rs$^ecGkwl&C;Q+9-;WnbmTO03vJ z{;qtZ@ha8AiR{#@DuW8gg-~AI2d3NiY&XKkw6La**mm3YXLDu?TWBF>3l;J_GdE>a zAOr4tXHQ;8tKLUWGbd!fI9xR{FBSq>L@j#FXU`gOJFt~-OR@EGw`|b7ui{J46o)+M zeZNb8Z=H^QCi*-&@zsgA@^;ND&kWBPu8Z<$*fS_K=+)rWa7CI;daJaV#aoNXWE+d} zEZHm#a}Dzc&5xTeH+Lqfq-ZI2!A4R>Qo2$G%Jw@2I?0#jl-|af6c0INIZl>VdY^QH zJ7zlAIqfYmyq0=xTW7_!ifsPua?5zj{IpJd-SzjS4@+~)M6bVj&emI4>Qx$o#=DB( z%kCG}O~zNnhujG{v#7<+bGn;1U))LjDDkGBAYwP-MRLo<$(pfC!Q=S;%MeyasuxUzUxY_Y0g+y(IluZr&ja5UYq*>p+uYx*eQ&UP(?oH(M z7EP*7dQ6_~yYyK3l5Coz60xnWQUB$xH|;yQE}e&Z4ip@<(zgo5-x`sGU?6e!*SfBk zWd`KUq2GyUf6(^3G^jnOsrCZ)!qMfiT1{DFS(8;AAkpxL8#NBPdq1_d|A$Il#69ZU|IiNO`*3RS%iRu6ohm_GeF^)=UEu*d~S<6fV` z87=o_PG$?|DhS9U5_HTdmg?vJ)a8@Q5sun6wLV~5H0R-a;`i_pkapE}%5(iaa+@uu zjO8qX&i)Zssd8BAzEY}*`DuU_6(i}+If zTl}z_e^UYOWbx8{@5nO9=JV_iJxgK>SRKKfrFvPTC?}aNIrd^a&fe{AbNC~8LVntg z=84B8k9uR(F21|8JRxvT;MLjE%u{CeU~z}xs)7UXVol$}y_|zWtUFHaW-HLV9Z@Rh z^~@@N!alL^Xq9x3g=gr#+DFH0Z!vj}bJ=meIT-yFPliPi_jX{Gj~D zvtH-Qxkc@V)xCC1b{5avp5Ycu7E0!J7KZ1IeN0&J+I!8?%Xi`dO9#s$yCiRESNYRt z;vHHjo0!fW<3_v>wp1^rz6${JsPfpIx!CYp(g%5XXl!onz}#jYM2~+|aKS6~CtLi* z@#2sJddXAChAFnm3(l_2cdQ<3w|BmM5%k%pcgwnq%9@UcO{Y;0J$lBDKZ(arwMM0$ zPYpS$@TqTq@8#0q5lqX#fpvs;clb!JIt-R0M>HxmTJ}ucCQTLhzFBX7+djDn;o|j{ z^j32z{)yFtii;J=h2?uZ%O``XZUwu|jcrO(Yw4e?`%gdH>AckU{9WI%12qBZ)9rmmb8IKWT9@Kx zW7g@j#w5iwo#Ht)o~Eu1hrizGw>b7WTfY_CDxD^>ba|<%P(&DV^y9Pfu9o%-?HP$v ziSc*6j$|&rtr-_B>TS5!u(|qSppxRgncWK$wE=wr;_t2utg{+A0y-wM?EdM-tZiHN zLcC~v{PG%>3)7!5O5k1q&_Cyaav(Wam?JO*F9kG~;EGcS^zxx5q5z<|GtdW(@x+lp zt~k7hx0b}ain|gZ53H7iy^00Y!bczH?qM9{hqDc`L}7wFF>tKJPHj%jKm^r+7mkDm z1$rIyCL#j0B)<4XQ00|khy>`13dvJTLU$z~$ic!Iq)+g}fz%Wf!5AnM3Q~hBsG-%+ zFeO!a5DW@agh16HiZCz~ih!vgU{KK4KM8G4s-)?Mbwk)74Zp^t{--73P9pgrAdrB7 z0EGZ01%e+Qq6mk>Ay60u1_M(yz{JDeBy=Fyn<%;JC zeZyiPxPv$^oHvO`wNw0UVCtY)SbR7AZF{}Eerri28TeBXd`0?OOCsv94-R63BN7hz zVQ>ci)Rsv8uJ=Te4erP2`~z21_1`)odAR+JpOu=wg@+6D_#3m8npLweb82;{HL1`L z`hGYxiQtDK5Dsdu&etC|F@vwvsgqOz3X-w+@Wv7Xh_afHUk!gupC3MPNHhtjO`YD< zi46n86j6%m2p9~ZtO|yzBA`$jC##yj_^_a^B`lhR{*4zUWrT_vt(Tv4fAvGadbl0_ zM_ztt()jp3WfA&>g9JYd0v4yOqzU<5@o%lDw^{4e%d9rh#z+rjVxX_82v=1F!xR*0 z-O%X$)(;97NHRws#`zIxMvyv=U$zH5H2&w(ZxshUzASSev>y?-GKsY$zRlwA`@;8S zzhd*FTVG;XqP=k1yR9v08~UT-M?1g!_|?HmtAFd@OU17aG$AW{(m{{^bA3U25cLV( z-Z%^ihyBkw^)EgB8@*fY^UniF+p^z|yCxQca3lD6p-I{vUT8cH;^U3ig#0M{0d{3Q zT38@Vyon^VHwI^d)TS0Fcz9qDif%ZVo1!WX?25%Hf>qGUieNNO)eVeQbW>M@Dnpf& zvFI<0^k?(GxJD8%hgSAxs_WH*5KF*N-T#)uC!oRq9GuZ6}ShzXY=K^Pry7=z}ymD}BLIgDJsqDr)MgieMPjRRyf1tgH-% zySkylZZIrb$qkNEQ+0Lw7UDN<{u0XAgGk*I5C1$5zpOM{obS)2|J#-J<=8=>F)K&0 zHfCiLUYU_UmHuefkM*^x;PKbt{AURMV*d9r0^D)l|7!bQb@fH-@0}0{ZlnOTA5Irf zogx4Hd|CDVv+=J%{=1vSYQ(R@K}7riXM^FUrmCi*jKhLe)YVkM7`U=4*wsxP2Udft zp;cT}amsFR)o+7MGnT)0ab<4NVE*|mRe~WDzn`TvT7U24XP*D~u>U86@uQ^}ceFPi zht-CB>)*G6U)%Nn^7uhvSg0x*u0-9flw83uxH1;(3dO2|)v2qDy3eSg)zw_T_3wW@ zezaK(WBgXK@bB9p!P_6__wQ_o)C7l`s*qN)BR4;S7YOa+bI=2WUfEnB{@&QHx0ml{ z5{N_q(Hxws^l5zjU!1F0oS(M}m|Hu35Kg(TKhn2BDzh@6CyY!b7 z`{yj?TW0jvtmkX?h+LhchAS&;B}1owouD3D)VnQ$hW)p+^Pg_5znK5DBENd4CYt{` z^TblOX`GrXdL{E**~@>Qd9F5<#@X*;5&qNUb2Z9u-2904Z5(KD)8v|(D_4I6HG8FI zQeQSUZEDv1moge}U+NrI?t2FheaSMFsPCSre-Oo$@2|GB^}pIW(y^tj|JC+~shzh6 zNgMVx+%Ls6Rx58PR9P7cC9CG6NS~M6?PFT(mUk$_!j|5z#6zaM9ABD>HD> zMMSH>z(q@guFSwi7ZI%j0~aj~x-tV7T|~4B3|zD{=*kRSbP>@iFmTb*per+Q(M3e7 zz`#XIgRacLMHdmR0s|K<4Z1P|7hOcO3JhGdH0a6((JC--(bAwRGjP#GM61BSMN5OO z%)mt#5v>9P7cC9CG6NS~M6?PFT(mUk%Ks7<=Z~M-z%Rle!J6n(_nvS`6+RJ zgXqpUm(B0w9t7K&7$8;n?V1tHH}`rMtGY}FF>&xuP-Ogv#Mp<4&Jw13vGT`Arx0q$o7+PV0v_}dT9 zzMoZq1$Ff+(IXiEW5kxSXAioL<;Or=qBjO#)CeR$)mFPX|It+JXb4=g zw*fh$05cszF9`xk+K>D$4rD4lRl4~;fugNNUL%UMsTWS06V&)T>6hhiNf`}!4ZpIj zP2PS4bY5RyGR(nd^ExjN0P9LdYBTvAuH1q5e)o{+b?(yI&7eZ}-LMX&E@aW2oA|fF ze+mOh(Gee`3{}ATXTwL#m}19dgtO0#KLXv?17Nr6yzRHRC<0Sz_5ow&{JN)%qY{di zxnIK~>sgAM#16zpP&QLW!;cQ&5$fpyYk_<5&JRxc$2mz_b>s3prR~&MinOag%q-{) zcr%M5a)Wnoae4n-&1)o0cTao4^Qn@Io9!vS_j&pkkqD%45(nrOI~l3OQXy+R+$Zy# z36$m;D|$SnaQwO#uN2UDi82!AT7Ce1%FkH66LI7aa~aUM#<5;M#ZUJ1i2(y8pm;x7 zhFh%l;Fd1wlHj;UDmv64?ylr>e@?VZvFh~M#>;Ze2EAOjRmaV|WZ3k^{M)mcBBN$; zj#b8Q1VOwSj<#7IPq)}#H1HN4+RqQbwvZpcF~}=tmP)#=z@$^C9%;_RC!*~6Xmq_z zX!X_nC0XEgTW!$3d%k`jg=&g!st;T-N)}=PJ?VcKG0g1UMCLoQ;gEjDncjSMN*#wL zYd=TseT`u+2jGNk+4|DkYRuDv7fOl-0n!(>bavSh{ z=is5(oDST*n0y1IcuN-D~#*YGNHe?C@Yptw{+# zKYaYoOYSv}SVhr#17Q;}K(uTxQ|x^J`-c+WMb#Lyk^?|}5leKcZmd?UK_xSG#!~og zOnN4u^Vz1Ljp@jQ@{UU-mIO^1`5DUbf!D0fQ^~q|0eaT*ZSnxpu&9k%!pQ{6FcieD zYbyW&0tb|J7nzb-BUs5~H&&ilvW6qT;l7(sR0>rc!z`}6V*`1O$hG(RThbjHL5-VN zz9Tb^n4J>ofEMCV^ zmw4u8JvQABK(mvAjvTN?nG0BZ$u)FesM|?)zKpAUm(?uWbxV#v24%>|N=2OC!>@C^ z6_nrf=D0dr=$ebVAUwlIl8S>nR zBSt272??8%;lT}R({uf$*TQASqjwS}U4qjfUD<=xvybtubK)mj=1CD0il4ebXKfpGTD-jk?1Mw>?~V0&qz73RQXb9PSaLqIDz$gX-KJ_OPp(w^Np^$dD0Q@ zkcQL}u2HAaq;a!bwMRTW3FkQ~{}35E)d{+B|AGkrC)8kM0*h}=dqNkly0*&8(T&Sh zEYVhBA<`04s>Hc7k@xXZkw+yu?sKQkoq-4vcQ8r(G3A~9ZZF2H4qnmS+n7j&iG#cJ zmA(@MZiJL?e-=eJR~o+|A9NXiGG1*;A?b?5r${H?{DxSAjy-MZFMyghi_3vo9Z^>E zmoeM#NN4fNefXTk;ZTh5)Myhit$TmJ=94S`N9ijLRbso;db>sYSn;8*w4}*IlVHCCReHfM`j)qM>v!%AbGyrK;wwHD;U{E}A`vFV zy)VTn8e(^;Ozi4)-wP2dElXiOuscdO zNgg(8oVkuX3ai|)0x zitl^43nVM!Q~>p<_1WM|_Hj-Nzs!=gaiQm-v}ZK<J^$w7nh)pLCTDFNWmZ^6WVw7J*FOC~<2;Z`4TIr*nIp zBVJBJnHLo-WYf@pUQ?;<+5p-uXf_DCBjW%SD@ct#7Q4jWAR#e-P}a>o$U>gyX+d|X zkxSCd=(brs*VhNlouln8?LJkFHM^wFUE{$fdiM2!cpeI68SBF;foZ#&F|(`7^<3&A zlAGQ7P$X)Q%W$}m`+)2YGIV@rA!PQ`Jx~zg&ZQenHn%39<(%{GBT^Uir^7^-v!6+o zOt>uDSfJMu*2%)g}pZu_Y9$WY(~xe7o`XT!5H-;IDsg^ zy{5gq7`TuQi3^3JoUMJ2%TA{*`;WGLWDD@9OK`{-FfZb4eN~So)=61fz^rcfp0@{d zPh$^RxcwP&Ylz$;)3feojG~UWA)9gSo^2nWfYFcLwd!P0dAdgzw*_r`9k~-L31E|M2xR7c|Zb8|GgoNfZ zXV>zj)G4Nd*Nd}m8vXM|hLX|74`|L&U)hAob10(8bysg4|5gf%&fdigISJxfm!2nZ zok9oag+Fagbp`L_DzgSXd2udHbhfQ$kM-u>{pUBm%~qYsob(EFda7|}o`5%gZ&;*@ zGI-9F+ZzRcU#Qaf;;m=l-R%ObIR_}WXLoNk;k0}vlxQ3^;Mmrb$NKWx)~W^70#~m) zk3YBe21S@f4n!-A4kd8$MJC*Mlz1oT#rTIn>QZxE11$n}8Jy4)%(&>uQ*6AD^>N8O zJ{dE=fGXY84`Z8KM3MIJM$BJDG2P9;zZSANk9jCjJ!WRJO>#W1uyhM|QB>mrXuL=o z31Tu<-NXq}RiQNN?(UBOE;7qWmN+L4*ykARcrpadk+}TMHW1wyR{Qbz(nZ+#$AHZ4 z;CleY{BHQGw2HWHWLK-?v-Me?rCLa>=an&&8$r!Yi@_4}wYS+iv~-sr>Vzmb&`rvK<+k2f6DZ^)W)S6cVy~GXm`^gS{ k)-nd^!PbD&j^%a0vFt@i&<;Fu<=6g93@nj_di#(64{eIDiU0rr literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/ext-zerotier/Makefile b/rooter/0optionalapps/ext-zerotier/Makefile new file mode 100644 index 0000000..b7cfa94 --- /dev/null +++ b/rooter/0optionalapps/ext-zerotier/Makefile @@ -0,0 +1,34 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-zerotier +PKG_VERSION:=4.500 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-zerotier + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + DEPENDS:=+zerotier + TITLE:=Install scripts for Zerotier + PKGARCH:=all +endef + +define Package/ext-zerotier/description + Install scripts for Zerotier +endef + + +define Build/Compile +endef + +define Package/ext-zerotier/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,ext-zerotier)) diff --git a/rooter/0optionalapps/ext-zerotier/files/etc/init.d/zerofire b/rooter/0optionalapps/ext-zerotier/files/etc/init.d/zerofire new file mode 100644 index 0000000..05b8693 --- /dev/null +++ b/rooter/0optionalapps/ext-zerotier/files/etc/init.d/zerofire @@ -0,0 +1,37 @@ +#!/bin/sh /etc/rc.common +. /lib/functions.sh +# Copyright (C) 2006 OpenWrt.org + +START=91 + +log() { + logger -t "ZeroTier Init.d : " "$@" +} + +check_config () { + WW=$(uci get firewall.zerozone) + if [ -z $WW ]; then + uci set firewall.zerozone=zone + uci set firewall.zerozone.name="zerotier" + uci set firewall.zerozone.forward="REJECT" + uci set firewall.zerozone.output="ACCEPT" + uci set firewall.zerozone.input="ACCEPT" + uci set firewall.zerozone.device="zt+" + uci set firewall.zerozone.masq="1" + uci set firewall.zerozone.mtu_fix="1" + + uci set firewall.zlzforward=forwarding + uci set firewall.zlzforward.dest="zerotier" + uci set firewall.zlzforward.src="lan" + + uci set firewall.zzlforward=forwarding + uci set firewall.zzlforward.dest="lan" + uci set firewall.zzlforward.src="zerotier" + uci commit firewall + /etc/init.d/firewall restart + fi +} + +start() { + check_config +} \ No newline at end of file diff --git a/rooter/0optionalapps/ext-zerotier/files/etc/uci-defaults/64-zerotier b/rooter/0optionalapps/ext-zerotier/files/etc/uci-defaults/64-zerotier new file mode 100644 index 0000000..eee1ac9 --- /dev/null +++ b/rooter/0optionalapps/ext-zerotier/files/etc/uci-defaults/64-zerotier @@ -0,0 +1,7 @@ +#!/bin/sh /etc/rc.common + +id=$(uci -q get custom.zerotier.networkid) +uci delete zerotier.zerotier.join +uci add_list zerotier.zerotier.join=$id +uci commit zerotier +/etc/init.d/zerotier restart diff --git a/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/controller/zerotier.lua b/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/controller/zerotier.lua new file mode 100644 index 0000000..74c997b --- /dev/null +++ b/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/controller/zerotier.lua @@ -0,0 +1,62 @@ +module("luci.controller.zerotier", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local fs = require "nixio.fs" + local lock = luci.model.uci.cursor():get("custom", "menu", "full") + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + if lock == "1" then + if fs.stat("/etc/config/zerotier") then + local page + if (multilock == "1" and rootlock == "1") then + page = entry({"admin", "adminmenu", "zerotier"}, template("zerotier/zerotier"), translate("Zerotier"), 7) + page.dependent = true + else + page = entry({"admin", "adminmenu", "zerotier"}, template("zerotier/zerotier"), translate("---Router ID"), 7) + page.dependent = true + end + end + end + end + + entry({"admin", "services", "getid"}, call("action_getid")) + entry({"admin", "services", "sendid"}, call("action_sendid")) + entry({"admin", "services", "get_ids"}, call("action_get_ids")) +end + +function action_getid() + local rv = {} + id = luci.model.uci.cursor():get("zerotier", "zerotier", "join") + rv["netid"] = id + secret = luci.model.uci.cursor():get("zerotier", "zerotier", "secret") + if secret == nil then + secret = "xxxxxxxxxx" + end + rv["routerid"] = string.sub(secret,1,10) + rv["password"] = luci.model.uci.cursor():get("custom", "zerotier", "password") + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_sendid() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/zerotier/netid.sh 1 " .. set) +end + +function action_get_ids() + local rv = {} + id = luci.model.uci.cursor():get("zerotier", "zerotier", "join") + rv["netid"] = id + secret = luci.model.uci.cursor():get("zerotier", "zerotier", "secret") + if secret ~= nil then + rv["routerid"] = string.sub(secret,1,10) + else + rv["routerid"] = "xxxxxxxxxx" + end + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end \ No newline at end of file diff --git a/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/admin_status/index/zero.htm b/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/admin_status/index/zero.htm new file mode 100644 index 0000000..47fd4b2 --- /dev/null +++ b/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/admin_status/index/zero.htm @@ -0,0 +1 @@ +<%+zerotier/zerotier1%> \ No newline at end of file diff --git a/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/zerotier/zerotier.htm b/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/zerotier/zerotier.htm new file mode 100644 index 0000000..2e7e15b --- /dev/null +++ b/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/zerotier/zerotier.htm @@ -0,0 +1,182 @@ +<%+header%> +<% +local sys = require "luci.sys" +local utl = require "luci.util" +local fs = require "nixio.fs" + +function showicon(lck) + if lck == 0 then + return resource .. "/icons/unlock1.png" + else + return resource .. "/icons/lock1.png" + end +end + +-%> + + + +
                +
                +

                <%:Router ID (Zerotier)%>

                +
                + + + + +
                + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                + +
                +
                +<%+footer%> \ No newline at end of file diff --git a/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/zerotier/zerotier1.htm b/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/zerotier/zerotier1.htm new file mode 100644 index 0000000..dfb07b6 --- /dev/null +++ b/rooter/0optionalapps/ext-zerotier/files/usr/lib/lua/luci/view/zerotier/zerotier1.htm @@ -0,0 +1,22 @@ + + +
                + <%:Router Info%> + + + +
                <%:Network ID%><%:Loading%> Collecting data...
                <%:Router ID%>
                +
                + diff --git a/rooter/0optionalapps/ext-zerotier/files/usr/lib/zerotier/netid.sh b/rooter/0optionalapps/ext-zerotier/files/usr/lib/zerotier/netid.sh new file mode 100644 index 0000000..8993552 --- /dev/null +++ b/rooter/0optionalapps/ext-zerotier/files/usr/lib/zerotier/netid.sh @@ -0,0 +1,21 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "NetID" "$@" +} + +ID=$2 + +log "$ID" + +if [ $ID = "xxxxxxxxxxxxxxxx" ]; then + uci set zerotier.zerotier.enabled='0' +else + uci set zerotier.zerotier.enabled='1' +fi + +uci delete zerotier.zerotier.join +uci add_list zerotier.zerotier.join=$ID +uci commit zerotier +/etc/init.d/zerotier restart diff --git a/rooter/0optionalapps/extramenu/Makefile b/rooter/0optionalapps/extramenu/Makefile new file mode 100644 index 0000000..8896ae0 --- /dev/null +++ b/rooter/0optionalapps/extramenu/Makefile @@ -0,0 +1,33 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=extramenu +PKG_VERSION:=4.500 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/extramenu + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + TITLE:=Install scripts for Extra menus + PKGARCH:=all +endef + +define Package/extramenu/description + Install scripts for Extra menus +endef + + +define Build/Compile +endef + +define Package/extramenu/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,extramenu)) diff --git a/rooter/0optionalapps/extramenu/files/etc/init.d/fullmenu b/rooter/0optionalapps/extramenu/files/etc/init.d/fullmenu new file mode 100644 index 0000000..d4b7188 --- /dev/null +++ b/rooter/0optionalapps/extramenu/files/etc/init.d/fullmenu @@ -0,0 +1,18 @@ +#!/bin/sh /etc/rc.common + +START=88 + +log() { + logger -t "FULL MENU" "$@" +} + +start() +{ + df=$(uci -q get custom.menu.default) + if [ -z $df ]; then + df=0 + fi + uci set custom.menu.full=$df + uci set custom.menu.enabled='1' + uci commit custom +} diff --git a/rooter/0optionalapps/extramenu/files/usr/lib/fullmenu/setmenu.sh b/rooter/0optionalapps/extramenu/files/usr/lib/fullmenu/setmenu.sh new file mode 100644 index 0000000..d5963e8 --- /dev/null +++ b/rooter/0optionalapps/extramenu/files/usr/lib/fullmenu/setmenu.sh @@ -0,0 +1,18 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Menu Change" "$@" +} + +full=$1 +source /etc/openwrt_release +twone=$(echo "$DISTRIB_RELEASE" | grep "21.02") + +if [ $full = "0" ]; then + fv="1" +else + fv="0" +fi +uci set custom.menu.full=$fv +uci commit custom \ No newline at end of file diff --git a/rooter/0optionalapps/extramenu/files/usr/lib/lua/luci/controller/fullmenu.lua b/rooter/0optionalapps/extramenu/files/usr/lib/lua/luci/controller/fullmenu.lua new file mode 100644 index 0000000..67488c4 --- /dev/null +++ b/rooter/0optionalapps/extramenu/files/usr/lib/lua/luci/controller/fullmenu.lua @@ -0,0 +1,39 @@ +module("luci.controller.fullmenu", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + entry({"admin", "adminmenu"}, firstchild(), translate("Administration"), 24).dependent=false + local df = luci.model.uci.cursor():get("custom", "menu", "default") + if df == '0' then + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + page = entry({"admin", "adminmenu", "fullmenu"}, template("fullmenu/fullmenu"), translate("Unlock / Lock Menus"), 5) + page.dependent = true + end + end + + entry({"admin", "menu", "getmenu"}, call("action_getmenu")) + entry({"admin", "menu", "setmenu"}, call("action_setmenu")) + +end + +function action_getmenu() + local rv = {} + id = luci.model.uci.cursor():get("custom", "menu", "full") + rv["full"] = id + password = luci.model.uci.cursor():get("custom", "menu", "password") + rv["password"] = password + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_setmenu() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/fullmenu/setmenu.sh " .. set) + +end \ No newline at end of file diff --git a/rooter/0optionalapps/extramenu/files/usr/lib/lua/luci/view/fullmenu/fullmenu.htm b/rooter/0optionalapps/extramenu/files/usr/lib/lua/luci/view/fullmenu/fullmenu.htm new file mode 100644 index 0000000..9511a60 --- /dev/null +++ b/rooter/0optionalapps/extramenu/files/usr/lib/lua/luci/view/fullmenu/fullmenu.htm @@ -0,0 +1,181 @@ +<%+header%> +<% +local sys = require "luci.sys" +local utl = require "luci.util" +local fs = require "nixio.fs" + +function showicon(lck) + if lck == 0 then + return resource .. "/icons/unlock1.png" + else + return resource .. "/icons/lock1.png" + end +end + +-%> + + + +
                +
                +

                <%:Unlock or Lock Administrative Menus%>

                +
                + + + + +
                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                + +
                +
                +<%+footer%> \ No newline at end of file diff --git a/rooter/0optionalapps/libmicroxml/Makefile b/rooter/0optionalapps/libmicroxml/Makefile new file mode 100644 index 0000000..b9fa2f3 --- /dev/null +++ b/rooter/0optionalapps/libmicroxml/Makefile @@ -0,0 +1,54 @@ +# +# Copyright (C) 2012-2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=libmicroxml +PKG_VERSION:=2015-03-18 +PKG_RELEASE=$(PKG_SOURCE_VERSION) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/pivasoftware/microxml.git +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=caa8d3e6887f5c70e54df555dd78e4e45cfa74cc +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz + +PKG_FIXUP:=autoreconf + +include $(INCLUDE_DIR)/package.mk + +define Package/libmicroxml + SECTION:=libs + CATEGORY:=Libraries + TITLE:=XML library + MAINTAINER:=Luka Perkov +endef + +define Package/libmicroxml/description + A micro sized XML library +endef + +CONFIGURE_ARGS += \ + --disable-threads \ + --enable-static \ + --enable-shared + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include + $(CP) $(PKG_BUILD_DIR)/microxml.h $(1)/usr/include + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_BUILD_DIR)/libmicroxml.so* $(1)/usr/lib + $(INSTALL_DIR) $(1)/usr/lib/pkgconfig + $(CP) $(PKG_BUILD_DIR)/microxml.pc $(1)/usr/lib/pkgconfig +endef + +define Package/libmicroxml/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_BUILD_DIR)/libmicroxml.so* $(1)/usr/lib +endef + +$(eval $(call BuildPackage,libmicroxml)) diff --git a/rooter/0optionalapps/luci-app-dnsmasq-ipset/Makefile b/rooter/0optionalapps/luci-app-dnsmasq-ipset/Makefile new file mode 100644 index 0000000..e6383bd --- /dev/null +++ b/rooter/0optionalapps/luci-app-dnsmasq-ipset/Makefile @@ -0,0 +1,34 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-dnsmasq-ipset +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/luci-app-dnsmasq-ipset + SECTION:=luci + CATEGORY:=LuCI + DEPENDS:=+dnsmasq-full + SUBMENU:=3. Applications + TITLE:=support for IP Set settings + PKGARCH:=all +endef + +define Package/luci-app-dnsmasq-ipset/description + Helper scripts for IP Set settings +endef + + +define Build/Compile +endef + +define Package/luci-app-dnsmasq-ipset/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,luci-app-dnsmasq-ipset)) diff --git a/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/etc/config/dnsmasq-ipset b/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/etc/config/dnsmasq-ipset new file mode 100644 index 0000000..83ec840 --- /dev/null +++ b/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/etc/config/dnsmasq-ipset @@ -0,0 +1,5 @@ +config ipsets + option ipset_name 'netflix' + option enabled '0' + list managed_domain 'netflix.com' + list managed_domain 'netflix.ca' \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/etc/init.d/dnsmasq-ipset b/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/etc/init.d/dnsmasq-ipset new file mode 100644 index 0000000..a993efd --- /dev/null +++ b/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/etc/init.d/dnsmasq-ipset @@ -0,0 +1,49 @@ +#!/bin/sh /etc/rc.common +# Author Qier LU + +START=55 + +DNSMASQ="/etc/dnsmasq.conf" + +gen_config_file() { + local section="${1}" + config_get ipset_name "${section}" "ipset_name" + sname="#$ipset_name-1" + ename="#$ipset_name-2" + sed -i "/$sname/,/$ename/d" "$DNSMASQ" + config_get enabled "${section}" "enabled" + if [ -z $enabled ]; then + enabled=0 + fi + if [ ${enabled} -eq 0 ] + then + return + fi + + handle_domain() { + local domain="${1}" + ipline=$ipline"${domain}/" + } + + ipline="ipset=/" + echo "#$ipset_name-1" >> "$DNSMASQ" + config_list_foreach "${section}" "managed_domain" handle_domain + echo "$ipline${ipset_name}" >> "$DNSMASQ" + echo "#$ipset_name-2" >> "$DNSMASQ" + ipset -N -exist "$ipset_name" iphash + /etc/init.d/dnsmasq reload +} + +gen_config_files() { + config_load 'dnsmasq-ipset' + config_foreach gen_config_file 'ipsets' +} + +start() { + gen_config_files +} + +reload() { + sleep 5 + gen_config_files +} diff --git a/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/usr/lib/lua/luci/controller/dnsmasq-ipset.lua b/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/usr/lib/lua/luci/controller/dnsmasq-ipset.lua new file mode 100644 index 0000000..e1514b0 --- /dev/null +++ b/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/usr/lib/lua/luci/controller/dnsmasq-ipset.lua @@ -0,0 +1,15 @@ + +-- Auther Qier LU + +module("luci.controller.dnsmasq-ipset", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + if not nixio.fs.access("/etc/config/dnsmasq-ipset") then + return + end + + entry({"admin", "network", "dnsmasq-ipset"}, cbi("dnsmasq-ipset"), _(translate("DNSmasq IP-Set")), 60).dependent = true +end diff --git a/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/usr/lib/lua/luci/model/cbi/dnsmasq-ipset.lua b/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/usr/lib/lua/luci/model/cbi/dnsmasq-ipset.lua new file mode 100644 index 0000000..fe6fff5 --- /dev/null +++ b/rooter/0optionalapps/luci-app-dnsmasq-ipset/files/usr/lib/lua/luci/model/cbi/dnsmasq-ipset.lua @@ -0,0 +1,24 @@ +-- Auther Qier LU + +local m, s, o, p + +m = Map("dnsmasq-ipset", translate("DNSmasq IPSet"), translate("IPSet lists for DNSMasq-full")) + +m.on_after_save = function(self) + luci.sys.call("/etc/init.d/dnsmasq-ipset reload &") +end + +s = m:section(TypedSection, "ipsets", translate("IPSet Lists")) +s.anonymous = true +s.addremove = true + +o = s:option(Value, "ipset_name", translate("IPSet Name")) +o.placeholder = "target ipset" +o.default = "rooter" +o.rmempty = false + +o = s:option(Flag, "enabled", translate("Enabled")) + +o = s:option(DynamicList, "managed_domain", translate("Managed Domain List")) + +return m diff --git a/rooter/0optionalapps/luci-app-hotspot/Makefile b/rooter/0optionalapps/luci-app-hotspot/Makefile new file mode 100644 index 0000000..eedaaf3 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/Makefile @@ -0,0 +1,34 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-hotspot +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/luci-app-hotspot + SECTION:=luci + CATEGORY:=LuCI + DEPENDS:=+iw +iwinfo + SUBMENU:=3. Applications + TITLE:=support for Wifi Hotspot Manager + PKGARCH:=all +endef + +define Package/luci-app-hotspot/description + Helper scripts to enable Wifi Hotspot Manager +endef + + +define Build/Compile +endef + +define Package/luci-app-hotspot/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,luci-app-hotspot)) diff --git a/rooter/0optionalapps/luci-app-hotspot/files/etc/config/travelmate b/rooter/0optionalapps/luci-app-hotspot/files/etc/config/travelmate new file mode 100644 index 0000000..23b3751 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/etc/config/travelmate @@ -0,0 +1,17 @@ + +config travelmate 'global' + option trm_debug '1' + option trm_maxwait '20' + option trm_maxretry '3' + option trm_iw '1' + option trm_auto '1' + option radio0 '2.4 Ghz' + option radio1 '5.8 Ghz' + option radcnt '2' + option reconn '1' + option connecting '0' + option ssid '5' + option trm_enabled '0' + option lost '0' + option delay '15' + diff --git a/rooter/0optionalapps/luci-app-hotspot/files/etc/hotplug.d/iface/99-travelmate-iface b/rooter/0optionalapps/luci-app-hotspot/files/etc/hotplug.d/iface/99-travelmate-iface new file mode 100644 index 0000000..1e1c211 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/etc/hotplug.d/iface/99-travelmate-iface @@ -0,0 +1,46 @@ +#!/bin/sh + +if [ "$ACTION" = ifup -a "$INTERFACE" = "wwan" ]; then + exit 1 +fi + +if [ "$ACTION" = ifdown -a "$INTERFACE" = "wwan" ]; then + conn=$(uci -q get travelmate.global.connecting) + wif=$(uci -q get travelmate.global.freq) + if [ "$conn" != "1" ]; then + uci -q set wireless.wwan$wif.ssid="Hotspot Manager Interface" + uci -q set wireless.wwan$wif.encryption="none" + uci -q set wireless.wwan$wif.key= + uci -q set wireless.wwan$wif.disabled=1 + uci -q commit wireless + wifilog "HOTSPOT" "Lost Connection" + ubus call network reload + disa=$(uci -q get travelmate.global.ssid) + # check for disconnect or lost connection + if [ "$disa" != "7" ]; then + uci set travelmate.global.ssid="9" # lost connection + reconn=$(uci -q get travelmate.global.reconn) + if [ "$reconn" != "0" ]; then + lost=$(uci -q get travelmate.global.lost) + if [ $reconn -eq 99 ]; then + lost="1" + fi + if [ $lost -le $reconn ]; then + let lost=$lost+1 + uci set travelmate.global.lost=$lost + uci set travelmate.global.delay="30" + uci commit travelmate + /usr/lib/hotspot/travelmate.sh & + exit 0 + fi + fi + fi + uci set travelmate.global.trm_enabled="0" + uci commit travelmate + fi + + debug="$(uci -q get travelmate.global.trm_debug)" + if [ $debug = "1" ]; then + wifilog "HOTSPOT" "hotplug (iface): action='$ACTION' interface='$INTERFACE'" + fi +fi \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/etc/init.d/travelmate b/rooter/0optionalapps/luci-app-hotspot/files/etc/init.d/travelmate new file mode 100644 index 0000000..7357870 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/etc/init.d/travelmate @@ -0,0 +1,90 @@ +#!/bin/sh /etc/rc.common + +. /lib/functions.sh + +START=98 + +log() { + wifilog "Hotspot Initialize" "$@" +} + +do_zone() { + local config=$1 + local name + local network + + config_get name $1 name + config_get network $1 network + newnet="$network" + if [ $name = wan ]; then + WWAN=$(echo "$network" | grep "wwan2") + if [ -z "$WWAN" ]; then + newnet="$newnet wwan2 wwan5" + uci_set firewall "$config" network "$newnet" + uci_commit firewall + /etc/init.d/firewall restart + fi + fi +} + +do_radio() { + local config=$1 + local channel + local hwmode + + config_get channel $1 channel + config_get hwmode $1 hwmode + if [ $hwmode = "11g" ]; then + w2=$(uci -q get wireless.wwan2.device) + if [ -z $w2 ]; then + uci set wireless.wwan2=wifi-iface + uci set wireless.wwan2.device=$config + uci set wireless.wwan2.network="wwan2" + uci set wireless.wwan2.mode="sta" + uci set wireless.wwan2.ssid="Hotspot Manager Interface" + uci set wireless.wwan2.encryption="none" + uci set wireless.wwan2.disabled="1" + uci commit wireless + fi + else + w2=$(uci -q get wireless.wwan5.device) + if [ -z $w2 ]; then + uci set wireless.wwan5=wifi-iface + uci set wireless.wwan5.device=$config + uci set wireless.wwan5.network="wwan5" + uci set wireless.wwan5.mode="sta" + uci set wireless.wwan5.ssid="Hotspot Manager Interface" + uci set wireless.wwan5.encryption="none" + uci set wireless.wwan5.disabled="1" + uci commit wireless + fi + fi +} + +start() +{ +log "Hotspot Firewall" + + PRO=$(uci get network.wwan2.proto) + if [ -z $PRO ]; then + uci set network.wwan2=interface + uci set network.wwan2.proto=dhcp + uci set network.wwan26=interface + uci set network.wwan26.proto=dhcpv6 + uci set network.wwan5=interface + uci set network.wwan5.proto=dhcp + uci set network.wwan56=interface + uci set network.wwan56.proto=dhcpv6 + uci commit network + fi + config_load firewall + config_foreach do_zone zone + config_load wireless + config_foreach do_radio wifi-device + uci set travelmate.global.lost="0" + uci set travelmate.global.delay="30" + uci set travelmate.global.state='0' + uci commit travelmate +} + + diff --git a/rooter/0optionalapps/luci-app-hotspot/files/etc/init.d/zhot b/rooter/0optionalapps/luci-app-hotspot/files/etc/init.d/zhot new file mode 100644 index 0000000..f610bee --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/etc/init.d/zhot @@ -0,0 +1,17 @@ +#!/bin/sh /etc/rc.common + +. /lib/functions.sh + +START=99 + +log() { + wifilog "Z-Hotspot " "$@" +} + +start() +{ + uci set travelmate.global.lost="0" + uci set travelmate.global.delay="30" + uci commit travelmate + /usr/lib/hotspot/travelmate.sh & +} diff --git a/rooter/0optionalapps/luci-app-hotspot/files/lib/upgrade/keep.d/hotspot b/rooter/0optionalapps/luci-app-hotspot/files/lib/upgrade/keep.d/hotspot new file mode 100644 index 0000000..5ed46ef --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/lib/upgrade/keep.d/hotspot @@ -0,0 +1 @@ +/etc/hotspot diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/bin/hkillall b/rooter/0optionalapps/luci-app-hotspot/files/usr/bin/hkillall new file mode 100644 index 0000000..3802082 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/bin/hkillall @@ -0,0 +1,9 @@ +#!/bin/sh +LOOKFOR=$1 +KILLLIST=$(ps | grep $LOOKFOR) +echo "$KILLLIST" | while read line; do + if `echo "$line" | grep "/$LOOKFOR" > /dev/null` ; then + PIDV=$(echo $line | grep -o "^[0-9]\{1,5\}" | grep -o "[0-9]\{1,5\}") + kill $PIDV + fi +done \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/band.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/band.sh new file mode 100644 index 0000000..a214c8a --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/band.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +BAND=$1 +if [ $BAND = "1" ]; then + BAND=2 +else + BAND=5 +fi + +/usr/lib/hotspot/enable.sh 0 + +uci set travelmate.global.freq=$BAND +uci set travelmate.global.ssid="6" +uci commit travelmate + +result=`ps | grep -i "travelmate.sh" | grep -v "grep" | wc -l` +if [ $result -ge 1 ] +then + wifilog "Band Change" "Travelmate already running" +else + /usr/lib/hotspot/travelmate.sh & +fi +uci set travelmate.global.ssid="Hotspot Manager Interface" +uci commit travelmate +exit 0 \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/copyhot.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/copyhot.sh new file mode 100644 index 0000000..83d87ef --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/copyhot.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +if [ -f "/tmp/hot" ]; then + rm -f /etc/hotspot + while IFS='|' read -r ssid encrypt key flag + do + echo $ssid"|"$encrypt"|"$key >> /etc/hotspot + done <"/tmp/hot" +fi diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/dis_hot.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/dis_hot.sh new file mode 100644 index 0000000..93e2f67 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/dis_hot.sh @@ -0,0 +1,15 @@ +#!/bin/sh +. /lib/functions.sh + +wif=$(uci -q get travelmate.global.freq) +rm -f /tmp/hotman +uci set travelmate.global.ssid="7" +uci set travelmate.global.state='' +uci set travelmate.global.bssid="" +uci set travelmate.global.key='' +uci commit travelmate +uci -q set wireless.wwan$wif.disabled=1 +uci set wireless.wwan$wif.ssid="Hotspot Manager Interface" +uci -q commit wireless +/etc/init.d/network reload + diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/enable.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/enable.sh new file mode 100644 index 0000000..e2b645f --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/enable.sh @@ -0,0 +1,42 @@ +#!/bin/sh +. /lib/functions.sh + +SET=$1 + +uci set travelmate.global.trm_enabled=$SET +uci commit travelmate + +wif=$(uci -q get travelmate.global.freq) + +if [ $SET = "1" ]; then + wifilog "Enable" "Connect Hotspot" + AU=$(uci get travelmate.global.trm_auto) + hkillall travelmate.sh + if [ $AU = "1" ]; then + uci set travelmate.global.ssid="8" + uci set travelmate.global.bssid="" + uci set travelmate.global.state='' + uci set travelmate.global.key='' + uci commit travelmate + uci -q set wireless.wwan$wif.encryption="none" + uci -q set wireless.wwan$wif.key= + uci set wireless.wwan$wif.ssid="Hotspot Manager Interface" + uci -q commit wireless + /usr/lib/hotspot/travelmate.sh & + fi +else + wifilog "Enable" "Disconnect Hotspot" + hkillall travelmate.sh + rm -f /tmp/hotman + uci set travelmate.global.ssid="7" + uci set travelmate.global.state="0" + uci set travelmate.global.key='' + uci set travelmate.global.bssid="" + uci set travelmate.global.trm_enabled="0" + uci commit travelmate + uci -q set wireless.wwan$wif.disabled=1 + uci set wireless.wwan$wif.ssid="Hotspot Manager Interface" + uci -q commit wireless + ubus call network.interface.wwan down + ubus call network reload +fi \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/getssid.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/getssid.sh new file mode 100644 index 0000000..c42fb01 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/getssid.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +wif=$(uci -q get travelmate.global.freq) +RADIO=$(uci get wireless.wwan$wif.device) +ap_list="$(ubus -S call network.wireless status | jsonfilter -e "@.$RADIO.interfaces[@.config.mode=\"ap\"].ifname")" +if [ -z $ap_list ]; then + wifi up + ap_list="$(ubus -S call network.wireless status | jsonfilter -e "@.$RADIO.interfaces[@.config.mode=\"ap\"].ifname")" +fi + +rm -f /tmp/ssidlist +for ap in ${ap_list} +do + iwinfo "${ap}" scan >> /tmp/ssidlist +done diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/inrange.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/inrange.sh new file mode 100644 index 0000000..77df595 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/inrange.sh @@ -0,0 +1,59 @@ +#!/bin/sh +. "/lib/functions.sh" + +log() { + wifilog "In Range" "$@" +} + +rm -f /tmp/hot1 +cnt=0 +trm_ifstatus="false" +while [ ${cnt} -lt 20 ] +do + trm_ifstatus="$(ubus -S call network.wireless status | jsonfilter -l1 -e '@.*.up')" + if [ "${trm_ifstatus}" = "true" ] + then + break + fi + cnt=$((cnt+1)) + sleep 1 +done + +wif=$(uci -q get travelmate.global.freq) +RADIO=$(uci get wireless.wwan$wif.device) +ap_list="$(ubus -S call network.wireless status | jsonfilter -e "@.$RADIO.interfaces[@.config.mode=\"ap\"].ifname")" + +trm_scanner="$(which iw)" +for ap in ${ap_list} +do + ssid_list="$(${trm_scanner} dev "${ap}" scan 2>/dev/null > /tmp/scan + cat /tmp/scan | awk '/SSID: /{if(!seen[$0]++){printf "\"";for(i=2; i<=NF; i++)if(i==2)printf $i;else printf " "$i;printf "\" "}}')" + + if [ -n "${ssid_list}" ] + then + if [ -f "/etc/hotspot" ]; then + while IFS='|' read -r ssid encrypt key + do + ssidq="\"$ssid\"" + if [ -n "$(printf "${ssid_list}" | grep -Fo "${ssidq}")" ] + then + echo $ssid"|"$encrypt"|"$key"|1" >> /tmp/hot1 + else + echo $ssid"|"$encrypt"|"$key"|0" >> /tmp/hot1 + fi + done <"/etc/hotspot" + fi + else + if [ -f "/etc/hotspot" ]; then + while IFS='|' read -r ssid encrypt key + do + echo $ssid"|"$encrypt"|"$key"|0" >> /tmp/hot1 + done <"/etc/hotspot" + fi + fi +done +if [ -f "/tmp/hot1" ]; then + mv -f /tmp/hot1 /tmp/hot +fi + + diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/manual.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/manual.sh new file mode 100644 index 0000000..63323d4 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/manual.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +MAN="$1" + +hkillall travelmate.sh + +/usr/lib/hotspot/dis_hot.sh +echo "$MAN" > /tmp/hotman +/usr/lib/hotspot/travelmate.sh & + diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/mode.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/mode.sh new file mode 100644 index 0000000..cbc9571 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/mode.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +SET=$1 + +rm -f /tmp/hotman +uci set travelmate.global.trm_auto=$SET +uci commit travelmate + +if [ $SET = "1" ]; then + result=`ps | grep -i "travelmate.sh" | grep -v "grep" | wc -l` + if [ $result -ge 1 ] + then + wifilog "HOTSPOT" "Travelmate already running" + else + /usr/lib/hotspot/travelmate.sh & + fi +else + hkillall travelmate.sh +fi \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/reconn.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/reconn.sh new file mode 100644 index 0000000..cef0a60 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/reconn.sh @@ -0,0 +1,11 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Reconnect" "$@" +} + +reconn=$1 +log "$reconn" +uci set travelmate.global.reconn=$reconn +uci commit travelmate \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/travelmate.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/travelmate.sh new file mode 100644 index 0000000..a31d4e0 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/hotspot/travelmate.sh @@ -0,0 +1,427 @@ +#!/bin/sh + +. /lib/functions.sh + +# travelmate, a wlan connection manager for travel router +# written by Dirk Brenken (dev@brenken.org) + +# This is free software, licensed under the GNU General Public License v3. +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# prepare environment +# +LC_ALL=C +PATH="/usr/sbin:/usr/bin:/sbin:/bin" +trm_ver="0.3.0" +trm_enabled=1 +trm_debug=0 +trm_maxwait=20 +trm_maxretry=1 +trm_iw=1 +trm_auto=$(uci -q get travelmate.global.trm_auto) + +check_wwan() { + uci set travelmate.global.ssid="0" + wif=$(uci -q get travelmate.global.freq) + if [ -z "$wif" ]; then + uci set travelmate.global.freq="2" + fi + uci commit travelmate + while [ ! -e /etc/config/wireless ] + do + sleep 1 + done + sleep 3 + f_check "ap" + cntx=0 + while [ "${trm_ifstatus}" != "true" ]; do + sleep 1 + f_check "ap" + let cntx=cntx+1 + if [ $cntx -ge 20 ]; then + break + fi + done + f_log "info" "AP Status ::: $trm_ifstatus" +} + +count_radio() { + local config=$1 + local channel + + config_get channel $1 channel + if [ $channel -gt 15 ]; then + uci set travelmate.global.radio5="5.8 Ghz" + else + uci set travelmate.global.radio2="2.4 Ghz" + fi + let radcnt=radcnt+1 +} + +check_radio() { + radcnt=0 + config_load wireless + config_foreach count_radio wifi-device + uci set travelmate.global.radcnt=$radcnt + uci commit travelmate +} + +f_envload() +{ + # source required system libraries + # + if [ -r "/lib/functions.sh" ] + then + . "/lib/functions.sh" + else + f_log "error" "required system library not found" + fi + + # load uci config and check 'enabled' option + # + option_cb() + { + local option="${1}" + local value="${2}" + eval "${option}=\"${value}\"" + } + config_load travelmate + + if [ ${trm_enabled} -ne 1 ] + then + f_log "info " "status ::: Hotspot Manager is currently disabled" + exit 0 + fi + + # check for preferred wireless tool + # + if [ ${trm_iw} -eq 1 ] + then + trm_scanner="$(which iw)" + else + trm_scanner="$(which iwinfo)" + fi + if [ -z "${trm_scanner}" ] + then + f_log "error" "status ::: no wireless tool for wlan scanning found, please install 'iw' or 'iwinfo'" + fi +} + +# function to bring down all STA interfaces +# +f_prepare() +{ + local config="${1}" + local mode="$(uci -q get wireless."${config}".mode)" + local network="$(uci -q get wireless."${config}".network)" + local disabled="$(uci -q get wireless."${config}".disabled)" + + if [ "${mode}" = "sta" ] && [ -n "${network}" ] + then + trm_stalist="${trm_stalist} ${config}_${network}" + if [ -z "${disabled}" ] || [ "${disabled}" = "0" ] + then + uci -q set wireless."${config}".disabled=1 + f_log "debug" "prepare ::: config: ${config}, interface: ${network}" + fi + fi +} + +f_check() +{ + local ifname cnt=0 mode="${1}" + trm_ifstatus="false" + + while [ ${cnt} -lt ${trm_maxwait} ] + do + wif=$(uci -q get travelmate.global.freq) + RADIO=$(uci get wireless.wwan$wif.device) + ifname="$(ubus -S call network.wireless status | jsonfilter -l 1 -e "@.$RADIO.interfaces[@.config.mode=\"${mode}\"].ifname")" + if [ -z $ifname ]; then + break + fi + if [ "${mode}" = "sta" ] + then + trm_ifstatus="$(ubus -S call network.interface dump | jsonfilter -e "@.interface[@.device=\"${ifname}\"].up")" + else + trm_ifstatus="$(ubus -S call network.wireless status | jsonfilter -l1 -e '@.*.up')" + fi + if [ "${trm_ifstatus}" = "true" ] + then + break + fi + cnt=$((cnt+1)) + sleep 1 + done + f_log "debug" "check ::: ${mode} name: ${ifname}, status: ${trm_ifstatus}, count: ${cnt}" +} + +# function to write to syslog +# +f_log() +{ + local class="${1}" + local log_msg="${2}" + + if [ -n "${log_msg}" ] && ([ "${class}" != "debug" ] || [ ${trm_debug} -eq 1 ]) + then + wifilog "HOTSPOT-[${trm_ver}] ${class}" "${log_msg}" + if [ "${class}" = "error" ] + then + wif=$(uci -q get travelmate.global.freq) + uci set travelmate.global.ssid="1" + uci commit travelmate + uci -q set wireless.wwan@wif.ssid="Hotspot Manager Interface" + uci -q set wireless.wwan$wif.encryption="none" + uci -q set wireless.wwan$wif.key= + uci -q commit wireless + #exit 255 + fi + fi +} + +ssid_list="" +ap_list="" +trm_stalist="" + +f_working_ap() { + f_check "ap" + wif=$(uci -q get travelmate.global.freq) + RADIO=$(uci get wireless.wwan$wif.device) + ap_list="$(ubus -S call network.wireless status | jsonfilter -e "@.$RADIO.interfaces[@.config.mode=\"ap\"].ifname")" + f_log "debug" "main ::: ap-list: ${ap_list}, sta-list: ${trm_stalist}" + if [ -z "${ap_list}" ] || [ -z "${trm_stalist}" ] + then + sleep 3 + f_check "ap" + ap_list="$(ubus -S call network.wireless status | jsonfilter -e "@.$RADIO.interfaces[@.config.mode=\"ap\"].ifname")" + f_log "debug" "main ::: ap-list: ${ap_list}, sta-list: ${trm_stalist}" + fi +} + +f_scan_ap() { + wif=$(uci -q get travelmate.global.freq) + radio=$(uci get wireless.wwan$wif.device) + # scan using AP radio + trm_iwinfo="$(command -v iwinfo)" + trm_maxscan="10" + scan_dev="$(ubus -S call network.wireless status 2>/dev/null | jsonfilter -q -l1 -e "@.${radio}.interfaces[0].ifname")" + ssid_list="$("${trm_iwinfo}" "${scan_dev:-${radio}}" scan 2>/dev/null | + awk 'BEGIN{FS="[[:space:]]"}/Address:/{var1=$NF}/ESSID:/{var2="";for(i=12;i<=NF;i++)if(var2==""){var2=$i}else{var2=var2" "$i}} + /Quality:/{split($NF,var0,"/")}/Encryption:/{if($NF=="none"){var3="+"}else{var3="-"}; + printf "%i %s %s %s\n",(var0[1]*100/var0[2]),var3,var1,var2}' | sort -rn | head -qn "${trm_maxscan}")" +} + +f_main() +{ + local config network ssid cnt=0 + wif=$(uci -q get travelmate.global.freq) + + trm_stalist="" + # check if wwan is connected + f_check "sta" + if [ "${trm_ifstatus}" == "true" ]; then + wifi down $(uci -q get wireless.wwan$wif.device) + f_check "sta" + f_log "info" "STA ${trm_ifstatus}" + while [ "${trm_ifstatus}" == "true" ]; do + sleep 1 + f_check "sta" + done + fi + if [ "${trm_ifstatus}" != "true" ] # not connected + then + uci set travelmate.global.state='1' + uci commit travelmate + f_check "ap" + f_log "info" "AP ${trm_ifstatus}" + if [ "${trm_ifstatus}" != "true" ]; then + wifi up $(uci -q get wireless.wwan$wif.device) + f_check "ap" + while [ "${trm_ifstatus}" != "true" ]; do + sleep 1 + f_check "ap" + done + fi + uci set travelmate.global.bssid="" + uci set travelmate.global.ssid="2" + uci commit travelmate + uci -q set wireless.wwan$wif.ssid="Hotspot Manager Interface" + uci -q set wireless.wwan$wif.encryption="none" + uci -q set wireless.wwan$wif.key= + uci -q commit wireless + ubus call network.interface.wwan$wif up + ubus call network reload + wifi up $(uci -q get wireless.wwan$wif.device) + sleep 5 + + # set disabled for wwan iface + config_load wireless + config_foreach f_prepare wifi-iface + if [ -n "$(uci -q changes wireless)" ] + then + uci -q commit wireless + ubus call network reload + fi + # check if AP working + f_working_ap + # AP or STA not working + if [ -z "${ap_list}" ] || [ -z "${trm_stalist}" ] + then + f_log "error" "main ::: no usable AP/STA configuration found" + + else + # single AP in list + for ap in ${ap_list} + do + #f_scan_ap + # repeat scan and connection + cnt=0 + delay=10 + reconn=$(uci -q get travelmate.global.reconn) + while [ ${cnt} -le $reconn ] + do + f_log "info" " Retry Count ${cnt}" + if [ $reconn -eq 99 ]; then + cnt=0 + fi + f_scan_ap + f_log "info" " SSID List ${ssid_list}" + # get list of Hotspots present + if [ -n "${ssid_list}" ]; then + if [ "$trm_auto" = "1" ]; then + FILE="/etc/hotspot" + else + FILE="/tmp/hotman" + fi + if [ -f "${FILE}" ]; then + # read list of selected Hotspots + while IFS='|' read -r ssid encrypt key + do + ssidq="\"$ssid\"" + # see if in scan list + if [ -n "$(printf "${ssid_list}" | grep -Fo "${ssidq}")" ]; then + # connect to Hotspot + uci set travelmate.global.bssid="$ssid" + uci set travelmate.global.ssid=">>> $ssid" + uci set travelmate.global.connecting="1" + uci commit travelmate + uci -q set wireless.wwan$wif.ssid="$ssid" + uci -q set wireless.wwan$wif.encryption=$encrypt + uci -q set wireless.wwan$wif.key=$key + uci -q set wireless.wwan$wif.disabled=0 + uci -q commit wireless + wifi up $(uci -q get wireless.wwan$wif.device) + ubus call network.interface.wwan$wif up + ubus call network reload + f_log "info " "main ::: wwan interface connected to uplink ${ssid}" + sleep 5 + # wait and check for good connection + f_check "ap" + f_log "info" "AP Status ::: $trm_ifstatus" + cntx=0 + while [ "${trm_ifstatus}" != "true" ]; do + sleep 1 + f_check "ap" + let cntx=cntx+1 + if [ $cntx -ge $delay ]; then + break + fi + f_log "info" "AP Status ::: $trm_ifstatus" + done + cntx=0 + #delay=$(uci -q get travelmate.global.delay) + f_check "sta" + f_log "info" "STA Status ${trm_ifstatus}" + while [ "${trm_ifstatus}" != "true" ]; do + sleep 1 + f_check "sta" + let cntx=cntx+1 + if [ $cntx -ge $delay ]; then + break + fi + f_log "info" "STA Status ${trm_ifstatus}" + done + + if [ "${trm_ifstatus}" = "true" ]; then + uci set travelmate.global.ssid="$ssid" + uci set travelmate.global.connecting="0" + uci set travelmate.global.lost="0" + uci set travelmate.global.state='2' + uci set travelmate.global.key=$key + uci set travelmate.global.trm_auto="1" + uci commit travelmate + # connection good + f_log "info" "Connected $ssid" + exit 0 + fi + # bad connection try next Hotspot in list + uci set travelmate.global.bssid="" + uci set travelmate.global.ssid="3" + uci commit travelmate + uci -q set wireless.wwan$wif.ssid="Hotspot Manager Interface" + uci -q set wireless.wwan$wif.encryption="none" + uci -q set wireless.wwan$wif.key= + uci -q set wireless.wwan$wif.disabled=1 + uci -q commit wireless + ubus call network.interface.wwan$wif down + ubus call network reload + f_log "info" "Try next in list" + fi + done <"${FILE}" + wifi up $(uci -q get wireless.wwan$wif.device) + f_check "ap" + while [ "${trm_ifstatus}" != "true" ]; do + f_check "ap" + sleep 1 + done + fi + fi + # No connection to any in list + cnt=$((cnt+1)) + if [ $reconn -gt 0 ]; then + f_log "info " "Sleep before retrying" + sleep 30 + fi + # repeat scan and connect + done + done + fi + # unable to connect + if [ "$trm_auto" = "1" ]; then + uci set travelmate.global.ssid="4" + else + uci set travelmate.global.ssid="5" + fi + reconn=$(uci -q get travelmate.global.reconn) + lost=$(uci -q get travelmate.global.lost) + if [ $reconn -eq 99 ]; then + lost="1" + fi + if [ $lost -gt $reconn ]; then + uci set travelmate.global.ssid="5" + fi + uci set travelmate.global.trm_enabled="0" + uci set travelmate.global.connecting="0" + uci set travelmate.global.lost="0" + uci set travelmate.global.state='0' + uci set travelmate.global.bssid="" + uci set travelmate.global.trm_auto="1" + uci commit travelmate + uci -q set wireless.wwan$wif.ssid="Hotspot Manager Interface" + uci -q set wireless.wwan$wif.encryption="none" + uci -q set wireless.wwan$wif.key= + uci -q commit wireless + f_log "info " "main ::: no wwan uplink found" + fi + # already connected + exit 0 +} + +check_wwan +check_radio +f_envload +f_main + +exit 0 \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/controller/hotspot.lua b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/controller/hotspot.lua new file mode 100644 index 0000000..75ceb27 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/controller/hotspot.lua @@ -0,0 +1,307 @@ +module("luci.controller.hotspot", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + entry({"admin", "hotspot"}, firstchild(), translate("Wifi Hotspot"), 29).dependent=false + page = entry({"admin", "hotspot", "hotspot"}, template("hotspot/hotspot"), _(translate("Hotspot Manager")), 5) + page.dependent = true + end + + entry({"admin", "services", "check_spot"}, call("action_check_spot")) + entry({"admin", "services", "set_mode"}, call("action_set_mode")) + entry({"admin", "services", "set_enabled"}, call("action_set_enabled")) + entry({"admin", "services", "disconnect"}, call("action_disconnect")) + entry({"admin", "services", "refreshlist"}, call("action_refresh")) + entry({"admin", "services", "moveup"}, call("action_moveup")) + entry({"admin", "services", "movedown"}, call("action_movedown")) + entry({"admin", "services", "addtolist"}, call("action_addtolist")) + entry({"admin", "services", "dellist"}, call("action_dellist")) + entry({"admin", "services", "editlist"}, call("action_editlist")) + entry({"admin", "services", "mancon"}, call("action_mancon")) + entry({"admin", "services", "bandchange"}, call("action_bandchange")) + entry({"admin", "services", "reconn"}, call("action_reconn")) +end + +function readhot() + line = nil + file = io.open("/tmp/hot", "r") + if file ~= nil then + repeat + tmp = file:read("*line") + if tmp ~= nil then + if line == nil then + line = tmp + else + line = line .. "|" .. tmp + end + end + until tmp == nil + file:close() + end + return line +end + +function action_check_spot() + local rv = {} + local freq = {} + local set = luci.http.formvalue("set") + auto = luci.model.uci.cursor():get("travelmate", "global", "trm_auto") + rv["auto"] = auto + rv["enabled"] = luci.model.uci.cursor():get("travelmate", "global", "trm_enabled") + rv["reconn"] = luci.model.uci.cursor():get("travelmate", "global", "reconn") + if rv["reconn"] == nil then + rv["reconn"] = "0" + end + + rv["ssid"] = luci.model.uci.cursor():get("travelmate", "global", "ssid") + if rv["ssid"] == nil then + rv["ssid"] = "No Connection" + end + fre = luci.model.uci.cursor():get("travelmate", "global", "freq") + encr = luci.model.uci.cursor():get("wireless", "wwan" .. fre, "encryption") + if encr == "none" then + rv["encryp"] = translate("Open") + else + rv["encryp"] = translate("Encrypted") + end + rv["disable"] = luci.model.uci.cursor():get("wireless", "wwan" .. fre, "disabled") + + dual = luci.model.uci.cursor():get("travelmate", "global", "radcnt") + rv["dual"] = dual + nrad = tonumber(dual) + for k = 0, nrad do + freq[k] = luci.model.uci.cursor():get("travelmate", "global", "radio" .. tostring(k)) + end + rv['freq'] = freq + + device = luci.model.uci.cursor():get("wireless", "wwan" .. fre, "device") + device = string.sub(device, 6, 7) + if fre == "2" then + fre="0" + else + fre="1" + end + rv["band"] = fre + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_set_mode() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/hotspot/enable.sh " .. set) +end + +function action_set_enabled() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/hotspot/enable.sh " .. set) +end + +function action_disconnect() + os.execute("/usr/lib/hotspot/dis_hot.sh") +end + +function action_refresh() + local rv = {} + os.execute("/usr/lib/hotspot/inrange.sh") + hotline = readhot() + if hotline == nil then + rv["empty"] = "1" + else + rv["empty"] = "0" + rv["hotline"] = hotline + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function movelist(direc, set, key) + local temp = {} + local rv = {} + local index = 0 + file = io.open("/tmp/hot", "r") + if file ~= nil then + repeat + tmp = file:read("*line") + if tmp ~= nil then + temp[index] = tmp + index = index + 1 + end + until tmp == nil + file:close() + if direc == 0 then + line2 = temp[set-1] + temp[set-1] = temp[set] + temp[set] = line2 + elseif direc == 1 then + line2 = temp[set+1] + temp[set+1] = temp[set] + temp[set] = line2 + elseif direc == 2 then + if index > 0 then + for i=set, index-2 do + temp[i] = temp[i+1] + end + end + index = index - 1 + elseif direc == 3 then + s, e = temp[set]:find("|") + name = temp[set]:sub(1, s-1) + cs, ce = temp[set]:find("|", e+1) + enc = temp[set]:sub(e+1, cs-1) + bs, be = temp[set]:find("|", ce+1) + ko = temp[set]:sub(ce+1, bs-1) + fl = temp[set]:sub(be+1) + temp[set] = name .. "|" .. enc .. "|" .. key .. "|" .. fl + end + if index < 0 then + --os.execute("rm -f /tmp/hot1; rm -f /etc/hotspot") + else + file = io.open("/tmp/hot", "w") + for i=0, index-1 do + file:write(temp[i], "\n") + end + file:close() + os.execute("/usr/lib/hotspot/copyhot.sh") + end + end +end + +function action_moveup() + local set = tonumber(luci.http.formvalue("set")) + local rv = {} + movelist(0, set) + hotline = readhot() + if hotline == nil then + rv["empty"] = "1" + else + rv["empty"] = "0" + rv["hotline"] = hotline + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_movedown() + local set = tonumber(luci.http.formvalue("set")) + local rv = {} + movelist(1, set) + hotline = readhot() + if hotline == nil then + rv["empty"] = "1" + else + rv["empty"] = "0" + rv["hotline"] = hotline + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_dellist() + local set = tonumber(luci.http.formvalue("set")) + local rv = {} + movelist(2, set) + hotline = readhot() + if hotline == nil then + rv["empty"] = "1" + else + rv["empty"] = "0" + rv["hotline"] = hotline + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_addtolist() + local set = luci.http.formvalue("set") + local rv = {} + + s, e = set:find("|") + ssid = set:sub(1, e-1) + + file = io.open("/etc/hotspot", "r") + if file ~= nil then + i = 0 + repeat + line = file:read("*line") + if line == nil then + break + else + s, e = line:find(ssid) + if s ~= nil then + i = 1 + break + end + end + until 1==0 + if i == 0 then + file = io.open("/etc/hotspot", "a") + file:write(set) + file:write("\n") + file:close() + end + else + file = io.open("/etc/hotspot", "w") + file:write(set) + file:write("\n") + file:close() + end + os.execute("/usr/lib/hotspot/inrange.sh") + hotline = readhot() + if hotline == nil then + rv["empty"] = "1" + else + rv["empty"] = "0" + rv["hotline"] = hotline + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_editlist() + local set = luci.http.formvalue("set") + local rv = {} + s, e = set:find("|") + sel = set:sub(1, s-1) + idx = tonumber(sel) + key = set:sub(e+1) + movelist(3, idx, key) + hotline = readhot() + if hotline == nil then + rv["empty"] = "1" + else + rv["empty"] = "0" + rv["hotline"] = hotline + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_mancon() + local set = luci.http.formvalue("set") + local rv = {} + os.execute("/usr/lib/hotspot/manual.sh \"" .. set .. "\"") +end + +function action_bandchange() + local set = luci.http.formvalue("set") + local rv = {} + os.execute("/usr/lib/hotspot/band.sh \"" .. set .. "\"") +end + +function action_reconn() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/hotspot/reconn.sh \"" .. set .. "\"") +end \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/controller/wifilog.lua b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/controller/wifilog.lua new file mode 100644 index 0000000..b192569 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/controller/wifilog.lua @@ -0,0 +1,33 @@ +module("luci.controller.wifilog", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + local page + page = entry({"admin", "hotspot", "wifilog"}, template("wifilog/wifilog"), _(translate("Hotspot Logging")), 61) + page.dependent = true + end + + entry({"admin", "status", "wifilog"}, call("action_wifilog")) +end + +function action_wifilog() + local file + local rv ={} + + file = io.open("/tmp/wifilog.log", "r") + if file ~= nil then + local tmp = file:read("*all") + rv["log"] = tmp + file:close() + else + rv["log"] = translate("No entries in log file") + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/view/hotspot/hotspot.htm b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/view/hotspot/hotspot.htm new file mode 100644 index 0000000..fae6a6b --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/view/hotspot/hotspot.htm @@ -0,0 +1,1139 @@ +<%- + +local sys = require "luci.sys" +local utl = require "luci.util" + +wifi = {} +scan = {} +numnet = 0 + +printf = function(s,...) + io.write(s:format(...)) + local ss = s:format(...) +end + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +function showicon() + return resource .. "/icons/encryption.png" +end + +function guess_wifi_signal(info) + local scale = scan[info]["quality"] + local icon + if scale < 15 then + icon = resource .. "/icons/signal-0.png" + elseif scale < 35 then + icon = resource .. "/icons/signal-0-25.png" + elseif scale < 55 then + icon = resource .. "/icons/signal-25-50.png" + elseif scale < 75 then + icon = resource .. "/icons/signal-50-75.png" + else + icon = resource .. "/icons/signal-75-100.png" + end + + return icon +end + +function scan_open(rrx, rry) + rony = 1 + if rry["encrypt"] == "Open" then + rony = 0 + end + ronx = 1 + if rrx["encrypt"] == "Open" then + ronx = 0 + end + if ronx < rony then + return true + end + if ronx > rony then + return false + end + ronx = rrx["quality"] + rony = rry["quality"] + if ronx > rony then + return true + end + return false +end + +function partition(arr, left, right) + local i = left + local j = right + local pivot = math.floor((left + right) / 2) + local tmp + while i <= j do + while scan_open(arr[i], arr[pivot]) do + i = i + 1 + end + while scan_open(arr[pivot], arr[j]) do + j = j - 1 + end + if i <= j then + tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp + i = i + 1 + j = j - 1 + end + end + return i, arr +end + +function quicksort(arr, left, right) + index, arr = partition(arr, left, right) + if left < (index - 1) then + quicksort(arr, left, index-1) + end + if index < right then + quicksort(arr, index, right) + end + return arr +end + +function build_scan(j, k) + scan[k]["channel"] = wifi[j]["channel"] + scan[k]["essid"] = wifi[j]["essid"] + scan[k]["signal"] = tonumber(wifi[j]["signal"]) + qc = tonumber(wifi[j]["quality"]) + qm = tonumber(wifi[j]["quality_max"]) + scan[k]["quality"] = math.floor((100 / qm) * qc) + scan[k]["ekey"] = wifi[j]["ekey"] + if wifi[j]["ekey"] == "none" then + scan[k]["encrypt"] = "Open" + scan[k]["encryption"] = wifi[j]["encryption"] + else + scan[k]["encrypt"] = wifi[j]["ekey"] + scan[k]["encryption"] = wifi[j]["encryption"] + end +end + +function get_networks() + luci.util.exec("/usr/lib/hotspot/getssid.sh") + file = io.open("/tmp/ssidlist", "r") + if file == nil then + numnet = 0 + return + end + i = 0 + cont = 2 + line = file:read("*line") + repeat + if line == nil then + cont = 0 + else + s, e = line:find("Cell ") + if s ~= nil then + cont = 1 + essid=nil + i = i + 1 + wifi[i] = {} + encryption = "none" + repeat + line = file:read("*line") + if line == nil then + cont = 0 + break + else + s, e = line:find("Cell ") + if s ~= nil then + break + else + s, e = line:find("ESSID:") + if s ~= nil then + ee = line:len() + essid = trim(line:sub(e+3, ee-1)) + end + s, e = line:find("Mode:") + if s ~= nil then + line1 = trim(line:sub(e+1)) + bs, be = line1:find(" ", 1) + mode = trim(line1:sub(1, bs)) + cs, ce = line1:find(" ") + line2 = trim(line1:sub(ce+1)) + s, e = line2:find("Channel:") + channel = trim(line2:sub(e+2)) + end + s, e = line:find("Signal:") + if s ~= nil then + line1 = trim(line:sub(e+1)) + bs, be = line1:find(" ", 1) + signal = trim(line1:sub(1, bs)) + cs, ce = line1:find(" ") + line2 = trim(line1:sub(ce+1)) + s, e = line2:find("Quality:") + cs, ce = line2:find("/", e) + quality = trim(line2:sub(e+1, ce-1)) + quality_max = trim(line2:sub(ce+1)) + end + s, e = line:find("Encryption:") + if s ~= nil then + cs, ce = line:find("WEP") + if cs == nil then + encrypt = trim(line:sub(e+2)) + s, e = encrypt:find("none") + if s ~= nil then + encryption = "none" + else + s, e = encrypt:find("mixed") + if s ~= nil then + encryption = "psk-mixed" + else + s, e = encrypt:find("WPA2") + if s ~= nil then + encryption = "psk2" + else + encryption = "psk" + end + end + end + else + cont = 2 + i = i - 1 + break + end + end + end + end + until 1==0 + else + line = file:read("*line") + end + end + if cont < 2 then + if i > 0 then + if essid ~= nil and mode == "Master" then + wifi[i]["essid"] = essid + wifi[i]["channel"] = channel + wifi[i]["signal"] = signal + wifi[i]["quality"] = quality + wifi[i]["quality_max"] = quality_max + wifi[i]["ekey"] = encrypt + wifi[i]["encryption"] = encryption + end + end + end + if cont == 0 then + break + end + cont = 2 + until 1==0 + file:close() + + k = 0 + if i > 0 then + for j=1, i do + if wifi[j]["essid"] ~= nil and tonumber(wifi[j]["quality"]) > 0 then + if k < 1 then + k = k+1 + scan[k] = {} + build_scan(j, k) + else + flag = 0 + for l=1, k do + if wifi[j]["essid"] == scan[l]["essid"] and wifi[j]["channel"] == scan[l]["channel"] and wifi[j]["ekey"] == scan[l]["ekey"] then + qc = tonumber(wifi[j]["quality"]) + qm = tonumber(wifi[j]["quality_max"]) + qual = math.floor((100 / qm) * qc) + if qual > scan[l]["quality"] then + build_scan(j, l) + end + flag = 1 + break + end + end + if flag == 0 then + k = k+1 + scan[k] = {} + build_scan(j, k) + end + end + end + end + scan = quicksort(scan, 1, k) + end + numnet = k +end + +-%> +<%+header%> + + + + +
                + +
                +

                <%:Wifi Hotspot Management%>

                +
                <%:Manage Your Wifi Hotspot Connections%>
                + + + +
                + + + + + + +
                  +  
                + + + + + +
                 
                + + + + + + + +
                <%:Reconnection Attempts on Dropped Connection%> + + +  
                + + + + + + + + + + + +
                 
                + + + + + + + +
                <%:Wifi Radio Frequency :%>
                + +  
                + + + + + +
                 
                + + + + + + + +
                <%:Current Wifi Hotspot : %>
                  + + + + + + + +
                  <%:Encryption : %>
                     
                    + + + + + +
                     
                    + + + + + + + + + +
                    <%:In Range%>
                    <%:Wifi Hotspot Networks%>
                     
                    + +
                      +
                    + +
                      +
                    •  
                    • +
                    • <%:No Wifi Hotspot Networks Selected%>
                    • +
                    •  
                    • +
                    + + + + + +
                     
                    + + + + + + + +
                    <%:Hotspot Name :%>
                       
                      + + + + + + + +
                      <%:Encrypted :%>
                         
                        + + + + + + + + +
                        <%:Key :%>
                           
                          + + + + + +
                           
                          + + + + + + + + + +
                           
                          + + + + + +
                           
                          + + <% get_networks() %> + + + + + +
                          <%:Available Networks : %><%=numnet%>
                          + <% if numnet > 0 then + for m=1, numnet do + data = scan[m]["essid"] .. "|" .. scan[m]["encryption"] + %> + + + + + + +
                          + +
                          + <%=scan[m]["quality"]%>% +
                          +
                          + <%=scan[m]["essid"]%>
                          + Channel: <%=scan[m]["channel"]%> | + Encryption: <%=scan[m]["encrypt"]%> +
                          + +
                          + <% end + end %> +
                          + +
                          +
                          + + + +
                          + + +<%+footer%> diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/view/wifilog/wifilog.htm b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/view/wifilog/wifilog.htm new file mode 100644 index 0000000..48bdb5f --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/lua/luci/view/wifilog/wifilog.htm @@ -0,0 +1,32 @@ +<%+header%> + + + + +
                          +

                          <%:Hotspot Logging%>

                          +
                          +
                          + <%:Log%> + + + + +
                          + +
                          + +
                          + +
                          + +<%+footer%> \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/rooter/log/wifilogger.sh b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/rooter/log/wifilogger.sh new file mode 100644 index 0000000..c9b7bc2 --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/lib/rooter/log/wifilogger.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +TEXT=$1 +DATE=$(date +%c) + +modlog="/tmp/wifilog.log" +tmplog="/tmp/twifilog" + +echo "$DATE : $TEXT" >> $modlog +lua $ROOTER/log/mrotate.lua $modlog $tmplog +mv $tmplog $modlog + diff --git a/rooter/0optionalapps/luci-app-hotspot/files/usr/sbin/wifilog b/rooter/0optionalapps/luci-app-hotspot/files/usr/sbin/wifilog new file mode 100644 index 0000000..962b1ce --- /dev/null +++ b/rooter/0optionalapps/luci-app-hotspot/files/usr/sbin/wifilog @@ -0,0 +1,7 @@ +#!/bin/sh + +name=$1 +text=$2 + +logger -t "$name" "$text" +/usr/lib/rooter/log/wifilogger.sh "$name $text" \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-hotspot/files/www/luci-static/resources/icons/encryption.png b/rooter/0optionalapps/luci-app-hotspot/files/www/luci-static/resources/icons/encryption.png new file mode 100644 index 0000000000000000000000000000000000000000..b45e2856202b579ca9ed66da9f3c5113ce654ee5 GIT binary patch literal 620 zcmV-y0+aoTP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0s%=xK~zXf#g#cu z96=a`Cj?oD#Y8|vV&DcCj6mE0La7Y(A2y2Oca zf^{(~K8X*3p5Sc=w>uV{qNYfGCFpQ2h6EZA+u}~JM4O^tpkZ+#=tEy}WQt|+$ajU; zc2L|4kJR9O7N||o2merHE*EP~14h$~5yZ&xm&HfX9?E#k#Ns8M$vj3ZD*p;9zhFdS zN$@+8C>6_qM_sHDfzRQnI9(h!D&i4Y_)x7p-!q;}q9D#R=1da3PMj`stt3&-SKyJetbYQtDTz`McZVnZ5o2OJlGK9ot)r0iBeIvZ>(>ExMGvP3e2q}O65*Y;26bTbzSB$ z!FO^h{L`n5$5DLIPydZnDm?;rd)~P-Mu8Rp0000 /tmp/iperf.pem") + options = options .. " --username " .. user .. " --rsa-public-key-path /tmp/iperf.pem" + end + if mode == "udp" then + options = options .. " -u -b " .. bitrate + end + if updown ~= "upload" then + options = options .. " -R" + end + local ipv = "4" + if proto == "ipv6" then + local ipv = "6" + end + + local t={} + for pt in ports:gmatch("([^,%s]+)") do + table.insert(t,pt) + end + local port = t[ math.random( #t ) ] + if password ~= "" then + iperf = io.popen("omr-iperf -P %s -%s -O %s -t %s -J -Z %s" % {parallel,ipv,omit,transmit,options}) + else + iperf = io.popen("iperf3 -c %s -P %s -%s -p %s -O %s -t %s -J -Z %s" % {ut.shellquote(addr),parallel,ipv,port,omit,transmit,options}) + end + if iperf then + while true do + local ln = iperf:read("*l") + if not ln then break end + luci.http.write(ln) + luci.http.write("\n") + end + end + return +end \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-iperf/files/usr/lib/lua/luci/view/iperf/test.htm b/rooter/0optionalapps/luci-app-iperf/files/usr/lib/lua/luci/view/iperf/test.htm new file mode 100644 index 0000000..03d0150 --- /dev/null +++ b/rooter/0optionalapps/luci-app-iperf/files/usr/lib/lua/luci/view/iperf/test.htm @@ -0,0 +1,185 @@ +<%+header%> + +<% + local uci = require("luci.model.uci").cursor() +%> + + + + +<% if stderr and #stderr > 0 then %>
                          <%=pcdata(stderr)%>
                          <% end %> +
                          +
                          +

                          <%:iPerf Speed Test%>

                          +
                          <%:Test Internet speeds using iPerf.%>
                          +
                          + <%:Settings%> +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          + <%:0 for unlimited.%> +
                          +
                          +
                          + +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          + <%:Server VPS IP is bypassed, so this will test only default route speed.%> +
                          +
                          +
                          + + + +
                          +
                          +
                          + +
                          + + +
                          +<%+footer%> diff --git a/rooter/0optionalapps/luci-app-iperf/files/usr/share/luci/menu.d/luci-app-iperf.json b/rooter/0optionalapps/luci-app-iperf/files/usr/share/luci/menu.d/luci-app-iperf.json new file mode 100644 index 0000000..dd6151e --- /dev/null +++ b/rooter/0optionalapps/luci-app-iperf/files/usr/share/luci/menu.d/luci-app-iperf.json @@ -0,0 +1,13 @@ +{ + "admin/services/iperf": { + "title": "iPerf", + "order": 10, + "action": { + "type": "template", + "path": "iperf/test" + }, + "depends": { + "acl": [ "luci-app-iperf" ] + } + } +} diff --git a/rooter/0optionalapps/luci-app-iperf/files/usr/share/rpcd/acl.d/luci-app-iperf.json b/rooter/0optionalapps/luci-app-iperf/files/usr/share/rpcd/acl.d/luci-app-iperf.json new file mode 100644 index 0000000..c851828 --- /dev/null +++ b/rooter/0optionalapps/luci-app-iperf/files/usr/share/rpcd/acl.d/luci-app-iperf.json @@ -0,0 +1,11 @@ +{ + "luci-app-iperf": { + "description": "Grant UCI access for luci-app-iperf", + "read": { + "uci": [ "iperf" ] + }, + "write": { + "uci": [ "iperf" ] + } + } +} \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/Makefile b/rooter/0optionalapps/luci-app-rootervpn/Makefile new file mode 100644 index 0000000..46f6d81 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/Makefile @@ -0,0 +1,34 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-rootervpn +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/luci-app-rootervpn + SECTION:=luci + CATEGORY:=LuCI + DEPENDS:=+openvpn-easy-rsa +openvpn-openssl +eoip + SUBMENU:=3. Applications + TITLE:=support for modified OpenVPN + PKGARCH:=all +endef + +define Package/luci-app-rootervpn/description + Helper scripts to enable OpenVPN support +endef + + +define Build/Compile +endef + +define Package/luci-app-rootervpn/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,luci-app-rootervpn)) diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/config/openvpn_recipes b/rooter/0optionalapps/luci-app-rootervpn/files/etc/config/openvpn_recipes new file mode 100644 index 0000000..68b6274 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/config/openvpn_recipes @@ -0,0 +1,293 @@ +# +# Routed point-to-point server +# +config openvpn_recipe b_server_tun_ptp + option _description "Basic point-to-point TUN VPN Server" + option _role "server" + option dev "tun-server" + option ifconfig "10.0.0.1 10.0.0.2" + option secret "shared-secret.key" + option keepalive "10 60" + option comp_lzo "yes" + option verb "3" + option mssfix "1420" + option topology "p2p" + +# +# Routed point-to-point client +# +config openvpn_recipe b_client_tun_ptp + option _description "Basic point-to-point TUN VPN Client" + option _role "client" + option client "1" + option dev "tun0" + list remote "vpnserver.example.org" + option ifconfig "10.0.0.2 10.0.0.1" + option secret "shared-secret.key" + option nobind "1" + option comp_lzo "yes" + option verb "3" + +# +# Routed multi-client server +# +config openvpn_recipe a_server_tun + option _description "Basic TUN VPN Server" + option _role "server" + option dev "tun-server" + option topology "subnet" + option port "1194" + option proto "udp" + option server "10.0.100.0 255.255.255.0" + option ca "/etc/openvpn/placeholder/placeholder.file" + option cert "/etc/openvpn/placeholder/placeholder.file" + option key "/etc/openvpn/placeholder/placeholder.file" + option dh "/etc/openvpn/placeholder/placeholder.file" + option keepalive "10 60" + option comp_lzo "yes" + option verb "3" + option mssfix "1420" + +# +# Routed client +# +config openvpn_recipe a_client_tun + option _description "Basic TUN VPN Client" + option _role "client" + option client "1" + option dev "tun0" + option proto "udp" + list remote "vpnserver.example.org" + option remote_cert_tls "server" + option comp_lzo "yes" + option nobind "1" + option persist_key "1" + option persist_tun "1" + option verb "3" + option reneg_sec "0" + option float "1" + option auth_user_pass "/etc/openvpn/placeholder/placeholder.file" + option ca "/etc/openvpn/placeholder/placeholder.file" + option cert "/etc/openvpn/placeholder/placeholder.file" + option key "/etc/openvpn/placeholder/placeholder.file" + +# +# Multi-client ethernet bridge server +# +config openvpn_recipe c_server_tap_bridge + option _description "Basic Server-Bridge TAP VPN Server" + option _role "server" + option dev "tap-server" + option port "1194" + option server_bridge "192.168.100.1 255.255.255.0 192.168.100.128 192.168.100.254" + option ca "/etc/openvpn/placeholder/placeholder.file" + option cert "/etc/openvpn/placeholder/placeholder.file" + option key "/etc/openvpn/placeholder/placeholder.file" + option dh "/etc/openvpn/placeholder/placeholder.file" + option keepalive "10 60" + option comp_lzo "yes" + option verb "3" + option mssfix "1420" + +# +# Ethernet bridge client +# +config openvpn_recipe c_client_tap_bridge + option _description "Basic Server-Bridge TAP VPN Client" + option _role "client" + option client "1" + option dev "tap0" + list remote "vpnserver.example.org" + option auth_user_pass "/etc/openvpn/placeholder/placeholder.file" + option ca "/etc/openvpn/placeholder/placeholder.file" + option cert "/etc/openvpn/placeholder/placeholder.file" + option key "/etc/openvpn/placeholder/placeholder.file" + option remote_cert_tls "server" + option comp_lzo "yes" + option nobind "1" + option persist_key "1" + option verb "3" + option reneg_sec "0" + option float "1" + +# +# OVPN Client +# +config openvpn_recipe d_ovpn_client + option _description "Client using OVPN File" + option _role "client" + option config "/etc/openvpn/placeholder/placeholder.file" + option auth_user_pass "/etc/openvpn/placeholder/placeholder.file" + +# +# NordVpn +# +config openvpn_recipe e_nordvpn_client_tun + option _description "Predefined Client for NordVPN" + option _role "client" + option config "/etc/openvpn/placeholder/placeholder.file" + option auth_user_pass "/etc/openvpn/placeholder/placeholder.file" + +# +# Private Internet Access Client +# +config openvpn_recipe e_pia_client_tun + option _description "Predefined Client for Private Internet Access" + option _role "client" + option client "1" + option dev "tun0" + option proto "udp" + list remote "us-example.privateinternetaccess.com" + option port "1198" + option resolv_retry "infinite" + option nobind "1" + option persist_key "1" + option persist_tun "1" + option cipher "aes-128-cbc" + option auth "sha1" + option tls_client "1" + option remote_cert_tls "server" + option auth_user_pass "/etc/openvpn/placeholder/placeholder.file" + option comp_lzo "yes" + option verb "1" + option reneg_sec "0" + option crl_verify "/etc/openvpn/pia/crl.rsa.2048.pem" + option ca "/etc/openvpn/pia/ca.rsa.2048.crt" + option disable_occ "1" + +# +# Windscribe +# +config openvpn_recipe e_windscribe_client_tun + option _description "Predefined Client for Windscribe" + option _role "client" + option client "1" + option dev "tun0" + option proto "udp" + list remote "example.windscribe.com" + option port "443" + option resolv_retry "infinite" + option nobind "1" + option persist_key "1" + option persist_tun "1" + option cipher "aes-256-cbc" + option auth "sha512" + option tls_client "1" + option remote_cert_tls "server" + option key_direction "1" + option auth_user_pass "/etc/openvpn/placeholder/placeholder.file" + option comp_lzo "yes" + option verb "2" + option reneg_sec "432000" + option tls_auth "/etc/openvpn/windscribe/ta.key" + option ca "/etc/openvpn/windscribe/ca.crt" + option redirect_gateway "def1" + +# +# ProtonVPN +# +config openvpn_recipe e_proton_client_tun + option _description "Predefined Client for ProtonVPN" + option _role "client" + option client "1" + option dev "tun0" + option proto "udp" + list remote "example.protonvpn.com" + option port "1194" + option resolv_retry "infinite" + option nobind "1" + option persist_key "1" + option persist_tun "1" + option cipher "aes-256-cbc" + option auth "sha512" + option tls_client "1" + option remote_cert_tls "server" + option key_direction "1" + option auth_user_pass "/etc/openvpn/placeholder/placeholder.file" + option comp_lzo "yes" + option verb "3" + option reneg_sec "0" + option tls_auth "/etc/openvpn/placeholder/placeholder.file" + option ca "/etc/openvpn/placeholder/placeholder.file" + option redirect_gateway "def1" + +# +# Mullvad +# +config openvpn_recipe e_mullvad_client_tun + option _description "Predefined Client for Mullvad" + option _role "client" + option client "1" + option dev "tun0" + option proto "udp" + list remote "example.mullvad.net" + option port "1194" + option resolv_retry "infinite" + option nobind "1" + option persist_key "1" + option persist_tun "1" + option cipher "aes-256-cbc" + option tls_client "1" + option remote_cert_tls "server" + option auth_user_pass "/etc/openvpn/placeholder/placeholder.file" + option comp_lzo "yes" + option verb "3" + option ca "/etc/openvpn/mullvad/mullvad_ca.crt" + option crl_verify "/etc/openvpn/mullvad/mullvad_crl.pem" + option redirect_gateway "def1" + +# +# AirVPN +# +config openvpn_recipe e_airvpn_client_tun + option _description "Predefined Client for AirVPN" + option _role "client" + option client "1" + option dev "tun0" + option proto "udp" + list remote "example.vpn.airdns.org" + option port "443" + option resolv_retry "infinite" + option nobind "1" + option persist_key "1" + option persist_tun "1" + option cipher "aes-256-cbc" + option route_delay "5" + option explicit_exit_notify "5" + option tls_client "1" + option remote_cert_tls "server" + option auth_user_pass "/etc/openvpn/placeholder/placeholder.file" + option comp_lzo "no" + option verb "3" + option key_direction "1" + option ca "/etc/openvpn/airvpn/ca.crt" + option cert "/etc/openvpn/airvpn/client.crt" + option key "/etc/openvpn/airvpn/client.key" + option tls_auth "/etc/openvpn/airvpn/ta.key" + +# +# Tunnelbear +# +config openvpn_recipe e_tunnelbear_client_tun + option _description "Predefined Client for Tunnelbear" + option _role "client" + option dev "tun0" + option proto "udp" + option port "443" + option client "1" + option nobind "1" + option persist_key "1" + option persist_tun "1" + option remote_cert_tls "server" + option reneg_sec "0" + option verb "1" + option comp_lzo "yes" + option auth_user_pass "/etc/openvpn/placeholder/placeholder.file" + option ca "/etc/openvpn/placeholder/placeholder.file" + option cert "/etc/openvpn/placeholder/placeholder.file" + option key "/etc/openvpn/placeholder/placeholder.file" + option remote "example.tunnelbear-ios.com" + option auth "SHA256" + option keysize "256" + option keep_alive "10 30" + option redirect_gateway "def1" diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/init.d/openvpn b/rooter/0optionalapps/luci-app-rootervpn/files/etc/init.d/openvpn new file mode 100644 index 0000000..543cdf1 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/init.d/openvpn @@ -0,0 +1,194 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2008-2013 OpenWrt.org +# Copyright (C) 2008 Jo-Philipp Wich +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. + +START=90 +STOP=10 + +USE_PROCD=1 +PROG=/usr/sbin/openvpn + +LIST_SEP=" +" +log() { + logger -t "OpenVpn init.d" "$@" +} + +if [ -e /tmp/openvpnboot ]; then + if [ -z "$1" ]; then + return + fi +fi + +UCI_STARTED= +UCI_DISABLED= + +append_param() { + local s="$1" + local v="$2" + case "$v" in + *_*_*_*) v=${v%%_*}-${v#*_}; v=${v%%_*}-${v#*_}; v=${v%%_*}-${v#*_} ;; + *_*_*) v=${v%%_*}-${v#*_}; v=${v%%_*}-${v#*_} ;; + *_*) v=${v%%_*}-${v#*_} ;; + esac + echo -n "$v" >> "/var/etc/openvpn-$s.conf" + return 0 +} + +append_bools() { + local p; local v; local s="$1"; shift + for p in $*; do + config_get_bool v "$s" "$p" + [ "$v" = 1 ] && append_param "$s" "$p" && echo >> "/var/etc/openvpn-$s.conf" + done +} + +append_params() { + local p; local v; local s="$1"; shift + for p in $*; do + config_get v "$s" "$p" + IFS="$LIST_SEP" + for v in $v; do + [ -n "$v" ] && [ "$p" != "push" ] && append_param "$s" "$p" && echo " $v" >> "/var/etc/openvpn-$s.conf" + [ -n "$v" ] && [ "$p" == "push" ] && append_param "$s" "$p" && echo " \"$v\"" >> "/var/etc/openvpn-$s.conf" + done + unset IFS + done +} + +append_list() { + local p; local v; local s="$1"; shift + + list_cb_append() { + v="${v}:$1" + } + + for p in $*; do + unset v + config_list_foreach "$s" "$p" list_cb_append + [ -n "$v" ] && append_param "$s" "$p" && echo " ${v:1}" >> "/var/etc/openvpn-$s.conf" + done +} + +section_enabled() { + config_get_bool enable "$1" 'enable' 0 + config_get_bool enabled "$1" 'enabled' 0 + [ $enable -gt 0 ] || [ $enabled -gt 0 ] +} + +openvpn_add_instance() { + local name="$1" + local dir="$2" + local conf="$3" + + uci set openvpn.$1.laststart="$(date +%s)" + uci commit openvpn + + procd_open_instance "$name" + procd_set_param command "$PROG" \ + --syslog "openvpn($name)" \ + --status "/var/run/openvpn.$name.status" \ + --cd "$dir" \ + --config "$conf" + procd_set_param file "$dir/$conf" + procd_set_param term_timeout 15 + procd_set_param respawn + procd_append_param respawn 3600 + procd_append_param respawn 5 + procd_append_param respawn -1 + procd_close_instance +} + +start_instance() { + local s="$1" + + config_get config "$s" config + config="${config:+$(readlink -f "$config")}" + + log "start instance $s" + if [ ! -e /tmp/openvpnboot ]; then + config_get_bool bootstart "$s" 'bootstart' 0 + if [ $bootstart -eq 0 ]; then + append UCI_DISABLED "$config" "$LIST_SEP" + return 1 + fi + fi + + section_enabled "$s" || { + append UCI_DISABLED "$config" "$LIST_SEP" + return 1 + } + + [ ! -d "/var/run" ] && mkdir -p "/var/run" + + if [ ! -z "$config" ]; then + append UCI_STARTED "$config" "$LIST_SEP" + openvpn_add_instance "$s" "${config%/*}" "$config" + return + fi + + [ ! -d "/var/etc" ] && mkdir -p "/var/etc" + [ -f "/var/etc/openvpn-$s.conf" ] && rm "/var/etc/openvpn-$s.conf" + + append_bools "$s" $OPENVPN_BOOLS + append_params "$s" $OPENVPN_PARAMS + append_list "$s" $OPENVPN_LIST + + openvpn_add_instance "$s" "/var/etc" "openvpn-$s.conf" + sleep 5 +} + +start_service() { + local instance="$1" + local instance_found=0 + + /etc/init.d/rootervpn start + + config_cb() { + local type="$1" + local name="$2" + if [ "$type" = "openvpn" ]; then + if [ -n "$instance" -a "$instance" = "$name" ]; then + instance_found=1 + fi + fi + } + + . /usr/share/openvpn/openvpn.options + config_load 'openvpn' + + if [ -n "$instance" ]; then + [ "$instance_found" -gt 0 ] || return + start_instance "$instance" + else + config_foreach start_instance 'openvpn' $1 + + + local path name + for path in /etc/openvpn/*.conf; do + if [ -f "$path" ]; then + name="${path##*/}"; name="${name%.conf}" + + # don't start configs again that are already started by uci + if echo "$UCI_STARTED" | grep -qxF "$path"; then + continue + + # don't start configs which are set to disabled in uci + elif echo "$UCI_DISABLED" | grep -qxF "$path"; then + logger -t openvpn "$name.conf is disabled in /etc/config/openvpn" + continue + fi + + openvpn_add_instance "$name" "${path%/*}" "$path" + + fi + done + fi + echo "0" > /tmp/openvpnboot +} + +service_triggers() { + procd_add_reload_trigger openvpn +} diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/init.d/rootervpn b/rooter/0optionalapps/luci-app-rootervpn/files/etc/init.d/rootervpn new file mode 100644 index 0000000..eb83a60 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/init.d/rootervpn @@ -0,0 +1,183 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +START=60 + +log() { + logger -t "OpenVPN : " "$@" +} + +check_config () { + log "Check Client Interfaces" + CHANGE="0" + WW=$(uci get network.VPN) + if [ -z $WW ]; then + uci set network.VPN=interface + uci set network.VPN.proto="none" + uci set network.VPN.ifname="tun0" + uci set network.VPN.auto="0" + CHANGE="1" + fi + WW=$(uci get network.VPNS) + if [ -z $WW ]; then + uci set network.VPNS=interface + uci set network.VPNS.proto="none" + uci set network.VPNS.ifname="tun-server" + uci set network.VPNS.auto="0" + CHANGE="1" + fi + WW=$(uci get network.TAP) + if [ -z $WW ]; then + uci set network.TAP=interface + uci set network.TAP.proto="none" + uci set network.TAP.ifname="tap0" + uci set network.TAP.auto="1" + LANIF=$(uci get network.lan.ifname) + TAP0=$(echo $LANIF | grep "tap0") + if [ -z "$TAP0" ]; then + uci set network.lan.ifname="$(uci get network.lan.ifname) tap0" + fi + CHANGE="1" + fi + WW=$(uci get network.TAPS) + if [ -z $WW ]; then + uci set network.TAPS=interface + uci set network.TAPS.proto="none" + uci set network.TAPS.ifname="tap-server" + uci set network.TAPS.auto="0" + LANIF=$(uci get network.lan.ifname) + TAP1=$(echo $LANIF | grep "tap-server") + if [ -z "$TAP1" ]; then + uci set network.lan.ifname="$(uci get network.lan.ifname) tap-server" + fi + CHANGE="1" + fi + if [ $CHANGE = "1" ]; then + uci commit network + /etc/init.d/network restart + fi + + CHANGE="0" + WW=$(uci get firewall.vpnzone) + if [ -z $WW ]; then + uci set firewall.vpnzone=zone + uci set firewall.vpnzone.name="VPN" + uci set firewall.vpnzone.forward="REJECT" + uci set firewall.vpnzone.output="ACCEPT" + uci set firewall.vpnzone.network="VPN" + uci set firewall.vpnzone.input="REJECT" + uci set firewall.vpnzone.masq="1" + uci set firewall.vpnzone.mtu_fix="1" + uci set firewall.vpnforward=forwarding + uci set firewall.vpnforward.dest="VPN" + uci set firewall.vpnforward.src="lan" + CHANGE="1" + fi + WW=$(uci get firewall.vpnzones) + if [ -z $WW ]; then + uci set firewall.vpnzones=zone + uci set firewall.vpnzones.name="VPNS" + uci set firewall.vpnzones.forward="REJECT" + uci set firewall.vpnzones.output="ACCEPT" + uci set firewall.vpnzones.network="VPNS" + uci set firewall.vpnzones.input="ACCEPT" + uci set firewall.vpnzones.masq="1" + uci set firewall.vpnzones.mtu_fix="1" + uci set firewall.vpnforwards=forwarding + uci set firewall.vpnforwards.dest="VPNS" + uci set firewall.vpnforwards.src="lan" + CHANGE="1" + fi + if [ $CHANGE = "1" ]; then + uci commit firewall + /etc/init.d/firewall restart + fi + WW=$(uci get openvpn.settings) + if [ -z $WW ]; then + uci set openvpn.settings=settings + uci set openvpn.settings.vpn2lan="0" + uci set openvpn.settings.vpns2lan="0" + uci set openvpn.settings.vpn2wan="0" + uci set openvpn.settings.country="CA" + uci set openvpn.settings.city="Abbotsford" + uci set openvpn.settings.organ="ROOter" + uci set openvpn.settings.days="3650" + uci set openvpn.settings.nclient='1' + uci commit openvpn + fi +} + +checkserver() { + log "Check Server Interfaces" + local s=$1 + if [ -z $s ]; then + return + fi + local SERVER="0" + local config=$(uci get openvpn.$s.config) + if [ ! -z $config ]; then + return + fi + local client=$(uci get openvpn.$s.client) + if [ -z $client ]; then + SERVER="1" + else + if [ $client = "0" ]; then + SERVER="1" + fi + fi + + if [ $SERVER = "1" ]; then + port=$(uci get openvpn.$s.port) + if [ -z $port ]; then + PORT="1194" + else + PORT=$port + fi + # look for rule for this port + INB="inbound"$PORT + RULE=$(uci get firewall.$INB) + if [ -z $RULE ]; then + uci set firewall.$INB=rule + uci set firewall.$INB.name=$INB + uci set firewall.$INB.target=ACCEPT + uci set firewall.$INB.src=* + uci set firewall.$INB.proto=udp + uci set firewall.$INB.dest_port=$PORT + uci commit firewall + /etc/init.d/firewall reload + fi + DEV=$(uci get openvpn.$s.dev) + if [ $DEV = "tun0" ]; then + uci set openvpn.$s.dev="tun1" + uci commit openvpn + else + + if [ $DEV = "tap0" ]; then + uci set openvpn.$s.dev="tap1" + uci commit openvpn + fi + fi + else + DEV=$(uci get openvpn.$s.dev) + if [ $DEV = "tun1" ]; then + uci set openvpn.$s.dev="tun0" + uci commit openvpn + else + if [ $DEV = "tap1" ]; then + uci set openvpn.$s.dev="tap0" + uci commit openvpn + fi + fi + fi +} + +start() { + check_config + checkserver + + if [ -d /etc/luci-uploads ]; then + rm -rfv /etc/luci-uploads + fi + ln -s /etc/openvpn /etc/luci-uploads +} \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/ca.crt b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/ca.crt new file mode 100644 index 0000000..cc37250 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/ca.crt @@ -0,0 +1,36 @@ +-----BEGIN CERTIFICATE----- +MIIGVDCCBDygAwIBAgIJAIzYQ+/kXyADMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNV +BAYTAklUMQswCQYDVQQIEwJJVDEQMA4GA1UEBxMHUGVydWdpYTETMBEGA1UEChMK +YWlydnBuLm9yZzEWMBQGA1UEAxMNYWlydnBuLm9yZyBDQTEeMBwGCSqGSIb3DQEJ +ARYPaW5mb0BhaXJ2cG4ub3JnMB4XDTE0MDQxMTEwMTU0NVoXDTI0MDQwODEwMTU0 +NVoweTELMAkGA1UEBhMCSVQxCzAJBgNVBAgTAklUMRAwDgYDVQQHEwdQZXJ1Z2lh +MRMwEQYDVQQKEwphaXJ2cG4ub3JnMRYwFAYDVQQDEw1haXJ2cG4ub3JnIENBMR4w +HAYJKoZIhvcNAQkBFg9pbmZvQGFpcnZwbi5vcmcwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDGG3ZrJbP61PNjGc4mjTx0TLkUjP7IXZ3wnpPjwF/lwK9n +HgRqoPL0KY/ABJuzMViD8ChtwthNfc7PuJ7vSPtN84lSJ4JGmTxvZkNeLQLZsu1F +f88OcSpjW5ErBM05iVBeF8/ljwaajgFfbgop9W/UK5yMji4qgq5KHxxXqsB8R4rC +eFpWHoNTwFjvXhtVyMgXiT9XAh/vBYim021m8onio4K48q7YRZ4qU8gvE79h5M0g +miIlt6v1vaZskw9cqIBbCYefGMsvBRk2x824ChPf6FazMwAnQHsuBHt6eXAARvfF +DBDanzPHlRSiCP6Je6Vod/MPyepiTZgjgk2VxYUc1ohNxEEGzPGTayeNzLJUldou +P4B+tjJ0Xly30+wvlahADlqjtz3CGQmKMj7btZjd+Uo61B7gau5YiXR/IO7ZpFAC +PCZJSbrwFs6rt9Kewqk8zslfVIro8oDndXRkVsa/c8Qmd6ZE7V+oMGl2OggdWOLl +mDEjkytzx+Bw2sSSalJRAQmOQO8V0anOI6jGYLuU2jnFDsnqSHuwIK11xb6iHmh7 +ONsRLUtQ+d64TzB00w2M0fCvGqUIp0N+lf7nsZKsEcU08OoHQYUuwX75ZEOYNSZJ +rqAXohcXdVUHqgRlJRErfSkjcGMM0yqjHkvopcnBIRXKMYTDVXvzRJboyJiVpQID +AQABo4HeMIHbMB0GA1UdDgQWBBTlFdcTqJ4x49Ew1/Ef9OJj0lDIiDCBqwYDVR0j +BIGjMIGggBTlFdcTqJ4x49Ew1/Ef9OJj0lDIiKF9pHsweTELMAkGA1UEBhMCSVQx +CzAJBgNVBAgTAklUMRAwDgYDVQQHEwdQZXJ1Z2lhMRMwEQYDVQQKEwphaXJ2cG4u +b3JnMRYwFAYDVQQDEw1haXJ2cG4ub3JnIENBMR4wHAYJKoZIhvcNAQkBFg9pbmZv +QGFpcnZwbi5vcmeCCQCM2EPv5F8gAzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB +BQUAA4ICAQCUVAQteCtgNQiZMXV0wCdqivlxlCCuj5sD+XvEuoDqb7dH70u1KQ90 +OAbkeotHlIbqJU10xWtvHEjnXg8QG5VOzaWnWWev+ivdPCkGWe8E7C8shsr4WMlA +EF8PPRtzOwCKayxjR713x+Tc2Sb6/rDsXcY5LV6RNmE9HWBM6IoHdqruR8PHkYge +2CPXMuLByEADri6xmvussAjCWEDplJNY7tQsUGT7vjrwrNSNBx/SvxkXnWBj0wYa +EwNu43jrjcRfM/3eGcKDX3cQqTfRQd3j3OA7zmJOXPeExRUIWZTNCvQItGy1TJdw +JTphflw15Bui4l2mYfDqK08zm4aJODrCjoQnVVzM5uOzSTOjmneI6AHj3MjjL3A/ +CFA5PCSquBhUycF4UEVf3aPGiV0vAthCBUqM4eKE+rbjWPSaxKghVdr/S82o7Wzz +9mGwnOZDqWk+8AWSsGBjamMk3mNMR45E9FRfPF/dyjOSbVyyTsd1VzlTFEJa0wjB +l3yq3r3iZAM3UtevocAyTEAu0vDYBbS6TgWmWEDOizybB0hNrTx5u/SEI0Kwcthc +rilYxD+n4kmV7TvIR0ZSaYpgYALWQV27zOqY51Ol4UT98WCOokge9HdoFcGJU2Uj +5VneGp14/Oklh7y6BxxxGC3zNGjKGNQYuHGTIgw1DoASmRUdkPkn/w== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/client.crt b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/client.crt new file mode 100644 index 0000000..7c8e434 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/client.crt @@ -0,0 +1,38 @@ +-----BEGIN CERTIFICATE----- +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 +qAZoGjCdOJq/IrQCq/95Cpw= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/client.key b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/client.key new file mode 100644 index 0000000..9f34129 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/client.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +59PFiE0grG3JNZa3g34RjxOtsoNrz3bH +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/ta.key b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/ta.key new file mode 100644 index 0000000..7d53ac5 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/airvpn/ta.key @@ -0,0 +1,18 @@ +-----BEGIN OpenVPN Static key V1----- +7bb7a23a0f5f28d01e792df68f1764ab +f2688719288808bf58e8a2d4f9354ecf +132625dfb895fc3f6330ae1e868e4dfa +c164c0931593d7f9a7da9595cf353433 +8896e1d0a987a0d19838944af8fea4e5 +215a3a0c76f4c67d5a4aee6a53be66a4 +c88b84f850030840fb30f8550ed8068f +35c1ef34ee8f40a0ea5862dfb6f8d3c5 +7ab5e27ac2799cf93e8765ff63cd8cd8 +6b391b813925cd373bb202796f64d16f +003d042ca828d1b07f18ba1d0cb0323d +df3ee9287e9e084e655699efb3cffa92 +3626946fa372e7beee245e7a95b4c1d8 +7d16cae685218d4b8afc019b22e41083 +476ee9883fe666d236301e55b2062551 +4d91c8a69467a758293994df1e6fa7ae +-----END OpenVPN Static key V1----- \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/mullvad/mullvad_ca.crt b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/mullvad/mullvad_ca.crt new file mode 100644 index 0000000..b795d91 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/mullvad/mullvad_ca.crt @@ -0,0 +1,109 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=NA, ST=None, L=None, O=Mullvad, CN=Mullvad CA/emailAddress=info@mullvad.net + Validity + Not Before: Mar 24 16:19:48 2009 GMT + Not After : Mar 22 16:19:48 2019 GMT + Subject: C=NA, ST=None, L=None, O=Mullvad, CN=master.mullvad.net/emailAddress=info@mullvad.net + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:c5:00:39:5d:fe:9b:0c:b7:ff:76:a4:93:bf:26: + 1b:d6:c8:4a:e5:3c:ce:1c:2c:16:80:a2:61:a6:e9: + 63:4b:70:a1:80:6f:0e:0c:bb:a9:b6:d1:bd:f5:a0: + 78:82:09:4d:94:22:aa:77:7c:09:36:42:cd:a5:a6: + 90:73:27:42:00:31:e4:d4:8b:49:36:65:a3:25:82: + b8:26:d7:d1:f5:b5:a9:be:57:93:9d:7c:d6:1c:df: + 9a:87:81:53:0b:17:81:d1:0d:ca:dc:4d:19:13:fa: + 11:e6:da:68:eb:81:05:39:e3:1e:3a:3f:fc:e2:64: + 3c:98:3c:89:a9:42:b3:30:70:57:56:a1:f5:08:b2: + 75:12:a0:36:93:9d:69:e9:7e:11:71:d9:1c:e8:7d: + ec:03:21:11:7a:0a:7a:03:35:ba:b8:b2:0c:3a:6f: + 57:88:62:45:3d:0c:6c:18:ff:21:49:37:ae:40:78: + 6d:45:52:29:ac:21:ad:4a:01:61:67:0b:01:c4:ac: + b0:88:97:52:ff:cb:3a:21:f0:14:2b:c1:79:8d:79: + 35:14:fc:9c:3f:6c:c9:62:fc:8c:c7:a8:51:34:75: + 1c:23:d5:db:b9:44:08:1c:0c:17:2c:21:2a:b4:29: + db:15:59:e7:a9:1c:d6:19:19:ef:e4:6b:ea:78:6d: + 76:8d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 75:8A:14:92:0D:F3:6E:B7:36:4F:8B:4F:15:6C:3F:18:15:90:64:DE + X509v3 Authority Key Identifier: + keyid:E1:63:B4:3E:55:A3:D2:37:5F:DE:3A:91:48:51:4B:20:1A:F2:9B:C5 + DirName:/C=NA/ST=None/L=None/O=Mullvad/CN=Mullvad CA/emailAddress=info@mullvad.net + serial:84:68:2E:A0:51:2A:BB:D4 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + a4:b4:62:3d:cb:7e:57:b3:bd:2a:41:e0:3b:94:d0:4c:08:69: + 8a:b1:73:15:13:20:c9:d7:b0:b6:5d:65:4a:4d:1d:27:cc:ca: + 11:0e:86:fa:65:61:26:39:c2:54:8e:da:eb:78:21:37:0e:c7: + a4:d2:17:8a:4b:ad:17:84:25:5e:24:0e:9a:81:ff:d1:1b:0e: + 32:9b:f4:81:e0:07:e9:8f:9d:c1:43:7f:40:30:01:07:7c:02: + c7:c4:9c:05:48:4c:bf:41:69:57:c1:d3:bb:a3:5a:01:17:96: + b0:c9:00:22:57:2f:84:da:45:33:6e:6c:2b:13:c5:af:75:a7: + b2:6b:71:6e:13:2c:97:0e:d9:93:da:6d:d9:34:c6:06:7d:0e: + e2:b8:d2:78:13:79:0f:ac:ac:a8:68:a9:72:73:7a:d8:ab:7b: + 0a:b0:54:b5:f3:ce:29:0d:47:82:0c:b4:d9:20:64:ff:ef:17: + 46:92:de:65:e8:67:ce:3a:92:de:e4:3e:99:73:9f:7a:7c:00: + 72:07:39:78:77:37:62:89:a2:db:24:fd:60:2a:e0:82:57:f6: + 55:94:f6:79:47:19:c9:13:3b:5d:b7:6b:66:14:d4:7d:3c:76: + 75:e9:a3:55:ba:b4:92:30:3b:ad:66:72:0c:39:4b:cc:95:a9: + bc:06:ef:2b +-----BEGIN CERTIFICATE----- +MIIEQjCCAyqgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBzMQswCQYDVQQGEwJOQTEN +MAsGA1UECBMETm9uZTENMAsGA1UEBxMETm9uZTEQMA4GA1UEChMHTXVsbHZhZDET +MBEGA1UEAxMKTXVsbHZhZCBDQTEfMB0GCSqGSIb3DQEJARYQaW5mb0BtdWxsdmFk +Lm5ldDAeFw0wOTAzMjQxNjE5NDhaFw0xOTAzMjIxNjE5NDhaMHsxCzAJBgNVBAYT +Ak5BMQ0wCwYDVQQIEwROb25lMQ0wCwYDVQQHEwROb25lMRAwDgYDVQQKEwdNdWxs +dmFkMRswGQYDVQQDExJtYXN0ZXIubXVsbHZhZC5uZXQxHzAdBgkqhkiG9w0BCQEW +EGluZm9AbXVsbHZhZC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDFADld/psMt/92pJO/JhvWyErlPM4cLBaAomGm6WNLcKGAbw4Mu6m20b31oHiC +CU2UIqp3fAk2Qs2lppBzJ0IAMeTUi0k2ZaMlgrgm19H1tam+V5OdfNYc35qHgVML +F4HRDcrcTRkT+hHm2mjrgQU54x46P/ziZDyYPImpQrMwcFdWofUIsnUSoDaTnWnp +fhFx2RzofewDIRF6CnoDNbq4sgw6b1eIYkU9DGwY/yFJN65AeG1FUimsIa1KAWFn +CwHErLCIl1L/yzoh8BQrwXmNeTUU/Jw/bMli/IzHqFE0dRwj1du5RAgcDBcsISq0 +KdsVWeepHNYZGe/ka+p4bXaNAgMBAAGjgdgwgdUwHQYDVR0OBBYEFHWKFJIN8263 +Nk+LTxVsPxgVkGTeMIGlBgNVHSMEgZ0wgZqAFOFjtD5Vo9I3X946kUhRSyAa8pvF +oXekdTBzMQswCQYDVQQGEwJOQTENMAsGA1UECBMETm9uZTENMAsGA1UEBxMETm9u +ZTEQMA4GA1UEChMHTXVsbHZhZDETMBEGA1UEAxMKTXVsbHZhZCBDQTEfMB0GCSqG +SIb3DQEJARYQaW5mb0BtdWxsdmFkLm5ldIIJAIRoLqBRKrvUMAwGA1UdEwQFMAMB +Af8wDQYJKoZIhvcNAQEFBQADggEBAKS0Yj3LflezvSpB4DuU0EwIaYqxcxUTIMnX +sLZdZUpNHSfMyhEOhvplYSY5wlSO2ut4ITcOx6TSF4pLrReEJV4kDpqB/9EbDjKb +9IHgB+mPncFDf0AwAQd8AsfEnAVITL9BaVfB07ujWgEXlrDJACJXL4TaRTNubCsT +xa91p7JrcW4TLJcO2ZPabdk0xgZ9DuK40ngTeQ+srKhoqXJzetirewqwVLXzzikN +R4IMtNkgZP/vF0aS3mXoZ846kt7kPplzn3p8AHIHOXh3N2KJotsk/WAq4IJX9lWU +9nlHGckTO123a2YU1H08dnXpo1W6tJIwO61mcgw5S8yVqbwG7ys= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEQjCCAyqgAwIBAgIJAIRoLqBRKrvUMA0GCSqGSIb3DQEBBQUAMHMxCzAJBgNV +BAYTAk5BMQ0wCwYDVQQIEwROb25lMQ0wCwYDVQQHEwROb25lMRAwDgYDVQQKEwdN +dWxsdmFkMRMwEQYDVQQDEwpNdWxsdmFkIENBMR8wHQYJKoZIhvcNAQkBFhBpbmZv +QG11bGx2YWQubmV0MB4XDTA5MDMyNDA2NDcyNVoXDTE5MDMyMjA2NDcyNVowczEL +MAkGA1UEBhMCTkExDTALBgNVBAgTBE5vbmUxDTALBgNVBAcTBE5vbmUxEDAOBgNV +BAoTB011bGx2YWQxEzARBgNVBAMTCk11bGx2YWQgQ0ExHzAdBgkqhkiG9w0BCQEW +EGluZm9AbXVsbHZhZC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDNNzZOrq+gMaA6wfyWdNFmxlM2OB1czwFgtPiDd9f6F8m6CGYBQog3Q2Wx3yAv +hxt/uchFBCKtYz6Yh59BCxXKfNAQT2uaMC6KAvKFgz0wppi4S8YbWg2KDelNO/Zv +Rb1QT4CBWMbtYzCQZvlJpHr2ZwuXG2OiT477oMyX5Hmf+iT0drmqi+wylRr7CRBs +LBu+fxLZ2LFD5g6MATuL3ql5JLIoVjlSqIgbld74pD4WUnM61HRwFsKoCEjq409Y +QNP1xO7BeaJu3uQvg/HJhXnGZxTatXhqvdCuAPQRppQ4UnkUzxdSTrfgM3hqMony +vX1vy0dX1S8iTQCIeyzAYNObAgMBAAGjgdgwgdUwHQYDVR0OBBYEFOFjtD5Vo9I3 +X946kUhRSyAa8pvFMIGlBgNVHSMEgZ0wgZqAFOFjtD5Vo9I3X946kUhRSyAa8pvF +oXekdTBzMQswCQYDVQQGEwJOQTENMAsGA1UECBMETm9uZTENMAsGA1UEBxMETm9u +ZTEQMA4GA1UEChMHTXVsbHZhZDETMBEGA1UEAxMKTXVsbHZhZCBDQTEfMB0GCSqG +SIb3DQEJARYQaW5mb0BtdWxsdmFkLm5ldIIJAIRoLqBRKrvUMAwGA1UdEwQFMAMB +Af8wDQYJKoZIhvcNAQEFBQADggEBAMjMAFPDeFOrQsvMXD/x+CuARwegS2PDZuB5 +f1Svw3YDF6cB1jlc0F12nh9SZxaYRwKIlpYoolLCOLoUCLwQJ0gsokxLV7G4gVb8 +dzETnNq4HG/QOPwPisjoOCaEmcd0tx1EkyNY0KLqFZTS0VdmDHCn89dDFA/6yuYI +5u04uJs7c/K4qaW7X6ajOOdneqjbtPeVOvx9DWXHxA0xz4Y+/w4laX/OTRD7jySq +K9fLfRliE5zsxzpUr5EWxAnqiABoWL71SiItk5fG8k3MJJ9SVr+YnTHmE7S4KNqu +4wTksvkb0Tmjae1lRSlMd6u2AulAxVcVKAod2QVffhj+hdkYM94= +-----END CERTIFICATE----- diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/mullvad/mullvad_crl.pem b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/mullvad/mullvad_crl.pem new file mode 100644 index 0000000..10e26dd --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/mullvad/mullvad_crl.pem @@ -0,0 +1,36 @@ +-----BEGIN X509 CRL----- +MIIGMTCCBRkwDQYJKoZIhvcNAQELBQAwezELMAkGA1UEBhMCTkExDTALBgNVBAgT +BE5vbmUxDTALBgNVBAcTBE5vbmUxEDAOBgNVBAoTB011bGx2YWQxGzAZBgNVBAMT +Em1hc3Rlci5tdWxsdmFkLm5ldDEfMB0GCSqGSIb3DQEJARYQaW5mb0BtdWxsdmFk +Lm5ldBcNMTcwNjIyMTQzMzEyWhcNMjcwNjIwMTQzMzEyWjCCBGswEgIBARcNMTcw +NjIyMTQzMzExWjASAgEDFw0xNzA2MjIxNDMzMTFaMBICASkXDTE3MDYyMjE0MzMx +MVowEwICDasXDTE3MDYyMjE0MzMxMVowEwICDawXDTE3MDYyMjE0MzMxMVowEwIC +Da0XDTE3MDYyMjE0MzMxMVowEwICDx4XDTE3MDYyMjE0MzMxMVowEwICGxsXDTE3 +MDYyMjE0MzMxMVowEwICPf4XDTE3MDYyMjE0MzMxMVowEwICSrUXDTE3MDYyMjE0 +MzMxMVowFAIDAbbXFw0xNzA2MjIxNDMzMTFaMBQCAwaeUBcNMTcwNjIyMTQzMzEx +WjAUAgMGnlUXDTE3MDYyMjE0MzMxMVowFAIDCheTFw0xNzA2MjIxNDMzMTFaMBQC +AwpvDBcNMTcwNjIyMTQzMzExWjAUAgML2jcXDTE3MDYyMjE0MzMxMVowFAIDDCfI +Fw0xNzA2MjIxNDMzMTFaMBQCAwwrKhcNMTcwNjIyMTQzMzExWjAUAgMMNWEXDTE3 +MDYyMjE0MzMxMVowFAIDDDViFw0xNzA2MjIxNDMzMTFaMBQCAwyXhRcNMTcwNjIy +MTQzMzExWjAUAgMM99UXDTE3MDYyMjE0MzMxMVowFAIDDPfWFw0xNzA2MjIxNDMz +MTFaMBQCAwz31xcNMTcwNjIyMTQzMzExWjAUAgMM9+MXDTE3MDYyMjE0MzMxMVow +FAIDDPfkFw0xNzA2MjIxNDMzMTFaMBQCAwz35RcNMTcwNjIyMTQzMzExWjAUAgMN +FHEXDTE3MDYyMjE0MzMxMVowFAIDDRSLFw0xNzA2MjIxNDMzMTFaMBQCAw1FfBcN +MTcwNjIyMTQzMzExWjAUAgMNUWcXDTE3MDYyMjE0MzMxMVowFAIDDVFoFw0xNzA2 +MjIxNDMzMTFaMBQCAw1RbBcNMTcwNjIyMTQzMzExWjAUAgMN2AoXDTE3MDYyMjE0 +MzMxMVowFAIDDdgLFw0xNzA2MjIxNDMzMTFaMBQCAw6G3xcNMTcwNjIyMTQzMzEx +WjAUAgMOkpwXDTE3MDYyMjE0MzMxMVowFAIDDpKdFw0xNzA2MjIxNDMzMTFaMBQC +Aw7DWhcNMTcwNjIyMTQzMzExWjAUAgMPFEEXDTE3MDYyMjE0MzMxMVowFAIDDyaP +Fw0xNzA2MjIxNDMzMTFaMBQCAw9D1xcNMTcwNjIyMTQzMzExWjAUAgMPzJQXDTE3 +MDYyMjE0MzMxMVowFAIDE3pTFw0xNzA2MjIxNDMzMTFaMBQCAxN6VBcNMTcwNjIy +MTQzMzExWjAUAgMTjroXDTE3MDYyMjE0MzMxMVowFAIDFIUDFw0xNzA2MjIxNDMz +MTFaMBQCAx7XBxcNMTcwNjIyMTQzMzExWjAUAgMgFScXDTE3MDYyMjE0MzMxMVow +FAIDImufFw0xNzA2MjIxNDMzMTFaMBQCAyPpNRcNMTcwNjIyMTQzMzExWjAUAgMk +eEgXDTE3MDYyMjE0MzMxMVowDQYJKoZIhvcNAQELBQADggEBAEdGuk5OitTepMQL +O2ugSjKl9le9ttuwiNkXCowYZwMpvOvk98RuhcgqwetDtxdMIi7koMIlbILfbIwA +VYvaV7HzpOzkL9D4RpE8GN3r1xjc+pjz5RN08Q+l/pRI9VeS2Bz6sstujqDMu0kT +LEzxtyiWGgdyYL0ykirahStLxmjc0JLLSsZXHuVJGmdJsphoEw/zgTRR02N7Q0gP +AmL6+i4mXY8OMaUMFWwKikliT+VAT23H1VPPUpS/5n3p+j15Hn5bI+rHyLmO2Ca7 +0UlcBbTVhoNMO25/6js5icRktebiaI0hq3Zofd5U80tGJnH+udIUEAq6CD/wUNqq +VcdW4oc= +-----END X509 CRL----- diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/pia/ca.rsa.2048.crt b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/pia/ca.rsa.2048.crt new file mode 100644 index 0000000..6deea60 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/pia/ca.rsa.2048.crt @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFqzCCBJOgAwIBAgIJAKZ7D5Yv87qDMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYD +VQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNV +BAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIElu +dGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3Mx +IDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkB +FiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzM1 +MThaFw0zNDA0MTIxNzM1MThaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex +EzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQg +QWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UE +AxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50 +ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVy +bmV0YWNjZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXD +L1L9tX6DGf36liA7UBTy5I869z0UVo3lImfOs/GSiFKPtInlesP65577nd7UNzzX +lH/P/CnFPdBWlLp5ze3HRBCc/Avgr5CdMRkEsySL5GHBZsx6w2cayQ2EcRhVTwWp +cdldeNO+pPr9rIgPrtXqT4SWViTQRBeGM8CDxAyTopTsobjSiYZCF9Ta1gunl0G/ +8Vfp+SXfYCC+ZzWvP+L1pFhPRqzQQ8k+wMZIovObK1s+nlwPaLyayzw9a8sUnvWB +/5rGPdIYnQWPgoNlLN9HpSmsAcw2z8DXI9pIxbr74cb3/HSfuYGOLkRqrOk6h4RC +OfuWoTrZup1uEOn+fw8CAwEAAaOCAVQwggFQMB0GA1UdDgQWBBQv63nQ/pJAt5tL +y8VJcbHe22ZOsjCCAR8GA1UdIwSCARYwggESgBQv63nQ/pJAt5tLy8VJcbHe22ZO +sqGB7qSB6zCB6DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpM +b3NBbmdlbGVzMSAwHgYDVQQKExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4G +A1UECxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAMTF1ByaXZhdGUg +SW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQpExdQcml2YXRlIEludGVybmV0IEFjY2Vz +czEvMC0GCSqGSIb3DQEJARYgc2VjdXJlQHByaXZhdGVpbnRlcm5ldGFjY2Vzcy5j +b22CCQCmew+WL/O6gzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQAn +a5PgrtxfwTumD4+3/SYvwoD66cB8IcK//h1mCzAduU8KgUXocLx7QgJWo9lnZ8xU +ryXvWab2usg4fqk7FPi00bED4f4qVQFVfGfPZIH9QQ7/48bPM9RyfzImZWUCenK3 +7pdw4Bvgoys2rHLHbGen7f28knT2j/cbMxd78tQc20TIObGjo8+ISTRclSTRBtyC +GohseKYpTS9himFERpUgNtefvYHbn70mIOzfOJFTVqfrptf9jXa9N8Mpy3ayfodz +1wiqdteqFXkTYoSDctgKMiZ6GdocK9nMroQipIQtpnwd4yBDWIyC6Bvlkrq5TQUt +YDQ8z9v+DMO6iwyIDRiU +-----END CERTIFICATE----- diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/pia/crl.rsa.2048.pem b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/pia/crl.rsa.2048.pem new file mode 100644 index 0000000..a58ef56 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/pia/crl.rsa.2048.pem @@ -0,0 +1,15 @@ +-----BEGIN X509 CRL----- +MIICWDCCAUAwDQYJKoZIhvcNAQENBQAwgegxCzAJBgNVBAYTAlVTMQswCQYDVQQI +EwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRl +cm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAw +HgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0 +ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRl +aW50ZXJuZXRhY2Nlc3MuY29tFw0xNjA3MDgxOTAwNDZaFw0zNjA3MDMxOTAwNDZa +MCYwEQIBARcMMTYwNzA4MTkwMDQ2MBECAQYXDDE2MDcwODE5MDA0NjANBgkqhkiG +9w0BAQ0FAAOCAQEAQZo9X97ci8EcPYu/uK2HB152OZbeZCINmYyluLDOdcSvg6B5 +jI+ffKN3laDvczsG6CxmY3jNyc79XVpEYUnq4rT3FfveW1+Ralf+Vf38HdpwB8EW +B4hZlQ205+21CALLvZvR8HcPxC9KEnev1mU46wkTiov0EKc+EdRxkj5yMgv0V2Re +ze7AP+NQ9ykvDScH4eYCsmufNpIjBLhpLE2cuZZXBLcPhuRzVoU3l7A9lvzG9mjA +5YijHJGHNjlWFqyrn1CfYS6koa4TGEPngBoAziWRbDGdhEgJABHrpoaFYaL61zqy +MR6jC0K2ps9qyZAN74LEBedEfK7tBOzWMwr58A== +-----END X509 CRL----- diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/placeholder/placeholder.file b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/placeholder/placeholder.file new file mode 100644 index 0000000..e88efe6 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/placeholder/placeholder.file @@ -0,0 +1,2 @@ +placeholder file +placeholder \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/windscribe/ca.crt b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/windscribe/ca.crt new file mode 100644 index 0000000..7edc133 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/windscribe/ca.crt @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF3DCCA8SgAwIBAgIJAMsOivWTmu9fMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNV +BAYTAkNBMQswCQYDVQQIDAJPTjEQMA4GA1UEBwwHVG9yb250bzEbMBkGA1UECgwS +V2luZHNjcmliZSBMaW1pdGVkMRMwEQYDVQQLDApPcGVyYXRpb25zMRswGQYDVQQD +DBJXaW5kc2NyaWJlIE5vZGUgQ0EwHhcNMTYwMzA5MDMyNjIwWhcNNDAxMDI5MDMy +NjIwWjB7MQswCQYDVQQGEwJDQTELMAkGA1UECAwCT04xEDAOBgNVBAcMB1Rvcm9u +dG8xGzAZBgNVBAoMEldpbmRzY3JpYmUgTGltaXRlZDETMBEGA1UECwwKT3BlcmF0 +aW9uczEbMBkGA1UEAwwSV2luZHNjcmliZSBOb2RlIENBMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAruBtLR1Vufd71LeQEqChgHS4AQJ0fSRner0gmZPE +r2TL5uWboOEWXFFoEUTthF+P/N8yy3xRZ8HhG/zKlmJ1xw+7KZRbTADD6shJPj3/ +uvTIO80sU+9LmsyKSWuPhQ1NkgNA7rrMTfz9eHJ2MVDs4XCpYWyX9iuAQrHSY6aP +q+4TpCbUgprkM3Gwjh9RSt9IoDoc4CF2bWSaVepUcL9yz/SXLPzFx2OT9rFrDhL3 +ryHRzJQ/tA+VD8A7lo8bhOcDqiXgEFmVOZNMLw+r167Qq1Ck7X86yr2mnW/6HK2g +JOvY0/SPKukfGJAiYZKdG+fe4ekyYcAVhDfPJg7rF9wUqPwUzejJyAs1K18JwX94 +Y8fnD6vQobjpC3qfHtwQP7Uj2AcI6QC8ytWDegV6UIkHXAMXBQSX5suSQoE11deG +32cy7nyp5vhgy31rTyNoopqlcCAhPm6k0jVVQbvXhLcpTSL8iCCoMdrP28i/xsfv +ktBAkl5giHMdK6hxqWgPI+Bx9uPIhRp3fJ2z8AgFm8g1ARB2ZzQ+OZZ2RUIkJuUK +hi2kUhgKSAQ+eF89aoqDjp/J1miZqGRzt4DovSZfQOeL01RkKHEibAPYCfgHG2ZS +woLoeaxE2vNZiX4dpXiOQYTOIXOwEPZzPvfTQf9T4Kxvx3jzQnt3PzjlMCqKk3Ai +pm8CAwEAAaNjMGEwHQYDVR0OBBYEFEH2v9F2z938Ebngsj9RkVSSgs45MB8GA1Ud +IwQYMBaAFEH2v9F2z938Ebngsj9RkVSSgs45MA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQAgI6NgYkVo5rB6yKStgHjj +ZsINsgEvoMuHwkM0YaV22XtKNiHdsiOmY/PGCRemFobTEHk5XHcvcOTWv/D1qVf8 +fI21WAoNQVH7h8KEsr4uMGKCB6Lu8l6xALXRMjo1xb6JKBWXwIAzUu691rUD2exT +1E+A5t+xw+gzqV8rWTMIoUaH7O1EKjN6ryGW71Khiik8/ETrP3YT32ZbS2P902iM +Kw9rpmuS0wWhnO5k/iO/6YNA1ZMV5JG5oZvZQYEDk7enLD9HvqazofMuy/Sz/n62 +ZCDdQsnabzxl04wwv5Y3JZbV/6bOM520GgdJEoDxviY05ax2Mz05otyBzrAVjFw9 +RZt/Ls8ATifu9BusZ2ootvscdIuE3x+ZCl5lvANcFEnvgGw0qpCeASLpsfxwq1dR +gIn7BOiTauFv4eoeFAQvCD+l+EKGWKu3M2y19DgYX94N2+Xs2bwChroaO5e4iFem +MLMuWKZvYgnqS9OAtRSYWbNX/wliiPz7u13yj+qSWgMfu8WPYNQlMZJXuGWUvKLE +XCUExlu7/o8D4HpsVs30E0pUdaqN0vExB1KegxPWWrmLcYnPG3knXpkC3ZBZ5P/e +l/2eyhZRy9ydiITF8gM3L08E8aeqvzZMw2FDSmousydIzlXgeS5VuEf+lUFA2h8o +ZYGQgrLt+ot8MbLhJlkp4Q== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/windscribe/ta.key b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/windscribe/ta.key new file mode 100644 index 0000000..dd556ac --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/etc/openvpn/windscribe/ta.key @@ -0,0 +1,18 @@ +-----BEGIN OpenVPN Static key V1----- +5801926a57ac2ce27e3dfd1dd6ef8204 +2d82bd4f3f0021296f57734f6f1ea714 +a6623845541c4b0c3dea0a050fe6746c +b66dfab14cda27e5ae09d7c155aa554f +399fa4a863f0e8c1af787e5c602a801d +3a2ec41e395a978d56729457fe6102d7 +d9e9119aa83643210b33c678f9d4109e +3154ac9c759e490cb309b319cf708cae +83ddadc3060a7a26564d1a24411cd552 +fe6620ea16b755697a4fc5e6e9d0cfc0 +c5c4a1874685429046a424c026db672e +4c2c492898052ba59128d46200b40f88 +0027a8b6610a4d559bdc9346d33a0a6b +08e75c7fd43192b162bfd0aef0c716b3 +1584827693f676f9a5047123466f0654 +eade34972586b31c6ce7e395f4b478cb +-----END OpenVPN Static key V1----- \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/lib/upgrade/keep.d/rootervpn b/rooter/0optionalapps/luci-app-rootervpn/files/lib/upgrade/keep.d/rootervpn new file mode 100644 index 0000000..30f20da --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/lib/upgrade/keep.d/rootervpn @@ -0,0 +1 @@ +/etc/openvpn/* diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/bin/ovpn-userpass b/rooter/0optionalapps/luci-app-rootervpn/files/usr/bin/ovpn-userpass new file mode 100644 index 0000000..615c85c --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/bin/ovpn-userpass @@ -0,0 +1,16 @@ +#!/bin/sh + +log() { + logger -t "UserPass : " "$@" +} + +conf="/etc/openvpn/ovpnauth.conf" + +userpass=`cat $1` +username=`echo $userpass | awk '{print $1}'` +password=`echo $userpass | awk '{print $2}'` + +log "$username $password" + + +exit 0 \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/bin/rkillall b/rooter/0optionalapps/luci-app-rootervpn/files/usr/bin/rkillall new file mode 100644 index 0000000..3802082 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/bin/rkillall @@ -0,0 +1,9 @@ +#!/bin/sh +LOOKFOR=$1 +KILLLIST=$(ps | grep $LOOKFOR) +echo "$KILLLIST" | while read line; do + if `echo "$line" | grep "/$LOOKFOR" > /dev/null` ; then + PIDV=$(echo $line | grep -o "^[0-9]\{1,5\}" | grep -o "[0-9]\{1,5\}") + kill $PIDV + fi +done \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/dns.sh b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/dns.sh new file mode 100644 index 0000000..b461228 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/dns.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +log() { + logger -t "Firewall Settings : " "$@" +} + +sleep 5 +LANOPENDNS=$(uci get openvpn.settings.lanopendns) +if [ -z $LANOPENDNS ]; then + LANOPENDNS="0" +fi +LANGOOGLE=$(uci get openvpn.settings.langoogle) +if [ -z $LANGOOGLE ]; then + LANGOOGLE="0" +fi +WANOPENDNS=$(uci get openvpn.settings.wanopendns) +if [ -z $WANOPENDNS ]; then + WANOPENDNS="0" +fi +WANGOOGLE=$(uci get openvpn.settings.wangoogle) +if [ -z $WANGOOGLE ]; then + WANGOOGLE="0" +fi + +if [ $LANOPENDNS = "1" -a $LANGOOGLE = "0" ]; then + uci del dhcp.lan.dhcp_option + uci add_list dhcp.lan.dhcp_option='6,208.67.222.222,208.67.220.220' +fi +if [ $LANOPENDNS = "0" -a $LANGOOGLE = "1" ]; then + uci del dhcp.lan.dhcp_option + uci add_list dhcp.lan.dhcp_option='6,8.8.8.8,8.8.4.4' +fi +if [ $LANOPENDNS = "1" -a $LANGOOGLE = "1" ]; then + uci del dhcp.lan.dhcp_option + uci add_list dhcp.lan.dhcp_option='6,8.8.8.8,8.8.4.4' + uci add_list dhcp.lan.dhcp_option='6,208.67.222.222,208.67.220.220' +fi +if [ $LANOPENDNS = "0" -a $LANGOOGLE = "0" ]; then + uci del dhcp.lan.dhcp_option +fi + +if [ $WANOPENDNS = "1" -a $WANGOOGLE = "0" ]; then + uci set network.wan.peerdns='0' + uci del network.wan.dns + uci add_list network.wan.dns='208.67.222.222' + uci add_list network.wan.dns='208.67.220.220' +fi +if [ $WANOPENDNS = "0" -a $WANGOOGLE = "1" ]; then + uci set network.wan.peerdns='0' + uci del network.wan.dns + uci add_list network.wan.dns='8.8.8.8' + uci add_list network.wan.dns='8.8.4.4' +fi +if [ $WANOPENDNS = "1" -a $WANGOOGLE = "1" ]; then + uci set network.wan.peerdns='0' + uci del network.wan.dns + uci add_list network.wan.dns='8.8.8.8' + uci add_list network.wan.dns='8.8.4.4' + uci add_list network.wan.dns='208.67.222.222' + uci add_list network.wan.dns='208.67.220.220' +fi +if [ $WANOPENDNS = "0" -a $WANGOOGLE = "0" ]; then + uci set network.wan.peerdns='1' + uci del network.wan.dns +fi +uci commit +/etc/init.d/network restart \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/firewall.sh b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/firewall.sh new file mode 100644 index 0000000..3ae0752 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/firewall.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +log() { + logger -t "Firewall Settings : " "$@" +} + +sleep 5 +VPN2LAN=$(uci get openvpn.settings.vpn2lan) +if [ -z $VPN2LAN ]; then + VPN2LAN="0" +fi +VPNS2LAN=$(uci get openvpn.settings.vpns2lan) +if [ -z $VPNS2LAN ]; then + VPNS2LAN="0" +fi +VPN2WAN=$(uci get openvpn.settings.vpn2wan) +if [ -z $VPN2WAN ]; then + VPN2WAN="0" +fi + +CHANGE="0" +if [ $VPN2LAN = "1" ]; then + WW=$(uci get firewall.vpnforward1) + if [ -z $WW ]; then + uci set firewall.vpnforward1=forwarding + uci set firewall.vpnforward1.dest="lan" + uci set firewall.vpnforward1.src="VPN" + CHANGE="1" + fi +else + WW=$(uci get firewall.vpnforward1) + if [ ! -z $WW ]; then + uci delete firewall.vpnforward1 + CHANGE="1" + fi +fi + +if [ $VPNS2LAN = "1" ]; then + WW=$(uci get firewall.vpnforwards1) + if [ -z $WW ]; then + uci set firewall.vpnforwards1=forwarding + uci set firewall.vpnforwards1.dest="lan" + uci set firewall.vpnforwards1.src="VPNS" + CHANGE="1" + fi +else + WW=$(uci get firewall.vpnforwards1) + if [ ! -z $WW ]; then + uci delete firewall.vpnforwards1 + CHANGE="1" + fi +fi + +if [ $VPN2WAN = "1" ]; then + WW=$(uci get firewall.vpnforward2) + if [ -z $WW ]; then + uci set firewall.vpnforward2=forwarding + uci set firewall.vpnforward2.dest="wan" + uci set firewall.vpnforward2.src="VPNS" + CHANGE="1" + fi +else + WW=$(uci get firewall.vpnforward2) + if [ ! -z $WW ]; then + uci delete firewall.vpnforward2 + CHANGE="1" + fi +fi + +if [ $CHANGE = "1" ]; then + uci commit firewall + /etc/init.d/firewall restart +fi \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/generate.sh b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/generate.sh new file mode 100644 index 0000000..17e1704 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/generate.sh @@ -0,0 +1,131 @@ +#!/bin/sh + + rm -f /tmp/easyrsa +### Step 1: Create the PKI directory tree + PKI_DIR="/tmp/openvpn" + +# if [ -d "$PKI_DIR" ]; then + rm -rfv "$PKI_DIR" +# fi + mkdir -p ${PKI_DIR} + chmod -R 0777 ${PKI_DIR} + mkdir -p ${PKI_DIR}/client + chmod -R 0777 ${PKI_DIR}/client + mkdir -p ${PKI_DIR}/server + chmod -R 0777 ${PKI_DIR}/server + mkdir -p ${PKI_DIR}/package + chmod -R 0777 ${PKI_DIR}/package + if [ -d "/www/package" ]; then + rm -rfv "/www/package" + fi + ln -s ${PKI_DIR}/package /www/package + cd ${PKI_DIR} + + touch index.txt + echo 1000 > serial + mkdir newcerts + + +### Step 2: Start with a clean configuration, and establish the basic variables + cp /etc/ssl/openssl.cnf ${PKI_DIR} + PKI_CNF=${PKI_DIR}/openssl.cnf + + CNT=$(uci get openvpn.settings.country) + CTY=$(uci get openvpn.settings.city) + ORG=$(uci get openvpn.settings.organ) + DAYS=$(uci get openvpn.settings.days) + CNAME=$(uci get openvpn.settings.comm) + EMAIL=$(uci get openvpn.settings.email) + UNIT=$(uci get openvpn.settings.unit) + UNSTRUC=$(uci get openvpn.settings.unstruc) + NCLIENT=$(uci get openvpn.settings.nclient) + if [ -z $NCLIENT ]; then + NCLIENT=1 + fi + + sed -i "/^dir/ s:=.*:= ${PKI_DIR}/:" ${PKI_CNF} + sed -i '/.*Name/ s:= match:= optional:' ${PKI_CNF} + + sed -i "/organizationName_default/ s:= .*:= $ORG:" ${PKI_CNF} + sed -i "/stateOrProvinceName_default/ s:= .*:= $CTY:" ${PKI_CNF} + sed -i "/countryName_default/ s:= .*:= $CNT:" ${PKI_CNF} + if [ ! -z $CNAME ]; then + sed -i -e "s/commonName = Common Name (e.g. server FQDN or YOUR name)/commonName = $CNAME/g" ${PKI_CNF} + fi + if [ ! -z $EMAIL ]; then + sed -i -e "s/emailAddress = Email Address/emailAddress = $EMAIL/g" ${PKI_CNF} + fi + if [ ! -z $UNIT ]; then + sed -i -e "s/organizationalUnitName = Organizational Unit Name (eg, section)/organizationalUnitName = $UNIT/g" ${PKI_CNF} + fi + if [ ! -z $UNSTRUC ]; then + sed -i -e "s/unstructuredName = An optional company name/unstructuredName = $UNSTRUC/g" ${PKI_CNF} + fi + + sed -i "/default_days/ s:=.*:= $DAYS:" ${PKI_CNF} + sed -i "/default_bits/ s:=.*:= 2048:" ${PKI_CNF} + + +cat >> ${PKI_CNF} <<"EOF" +############################################################################### +### Check via: openssl x509 -text -noout -in *.crt | grep 509 -A 1 +[ my-server ] +# X509v3 Key Usage: Digital Signature, Key Encipherment +# X509v3 Extended Key Usage: TLS Web Server Authentication + keyUsage = digitalSignature, keyEncipherment + extendedKeyUsage = serverAuth + +[ my-client ] +# X509v3 Key Usage: Digital Signature +# X509v3 Extended Key Usage: TLS Web Client Authentication + keyUsage = digitalSignature + extendedKeyUsage = clientAuth + +EOF + + echo "1" > /tmp/easyrsa + +### Step 3a: Create the CA, Server, and Client certificates (*without* using easy-rsa): +# pkitool --initca ## equivalent to the 'build-ca' script + openssl req -batch -nodes -new -keyout "ca.key" -out "ca.crt" -x509 -days $DAYS -config ${PKI_CNF} 2> /dev/null ## x509 (self-signed) for the CA + + echo "2" > /tmp/easyrsa +# pkitool --server my-server ## equivalent to the 'build-key-server' script + openssl req -batch -nodes -new -keyout "$ORG-server.key" -out "$ORG-server.csr" -subj "/CN=$ORG-server" -config ${PKI_CNF} 2> /dev/null + openssl ca -batch -keyfile "ca.key" -cert "ca.crt" -in "$ORG-server.csr" -out "$ORG-server.crt" -config ${PKI_CNF} -extensions my-server 2> /dev/null + + echo "3" > /tmp/easyrsa +# pkitool my-client ## equivalent to the 'build-key' script + COUNTER=$NCLIENT + while [ $COUNTER -gt 0 ]; do + openssl req -batch -nodes -new -keyout "$ORG-client$COUNTER.key" -out "$ORG-client$COUNTER.csr" -subj "/CN=$ORG-client$COUNTER" -config ${PKI_CNF} 2> /dev/null + openssl ca -batch -keyfile "ca.key" -cert "ca.crt" -in "$ORG-client$COUNTER.csr" -out "$ORG-client$COUNTER.crt" -config ${PKI_CNF} -extensions my-client 2> /dev/null + let COUNTER=COUNTER-1 + done + + chmod 0600 "ca.key" + chmod 0600 "$ORG-server.key" + COUNTER=$NCLIENT + while [ $COUNTER -gt 0 ]; do + chmod 0600 "$ORG-client$COUNTER.key" + cp "$ORG-client$COUNTER.crt" ${PKI_DIR}/client + cp "$ORG-client$COUNTER.key" ${PKI_DIR}/client + let COUNTER=COUNTER-1 + done + + cp "ca.crt" ${PKI_DIR}/client + cp "ca.crt" ${PKI_DIR}/server + cp "$ORG-server.key" ${PKI_DIR}/server + cp "$ORG-server.crt" ${PKI_DIR}/server + + echo "4" > /tmp/easyrsa +### Step 4: Create the Diffie-Hellman parameters + openssl dhparam -out dh2048.pem 2048 2> /dev/null + cp "dh2048.pem" ${PKI_DIR}/server + + echo "5" > /tmp/easyrsa + + + tar -czf ${PKI_DIR}/package/certificates.tar.gz ./client ./server + sleep 7 + echo "6" > /tmp/easyrsa \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/stop.sh b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/stop.sh new file mode 100644 index 0000000..e9088c9 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/stop.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +result=`ps | grep -i "generate.sh" | grep -v "grep" | wc -l` +if [ $result -ge 1 ]; then + rkillall generate.sh + rm -f /tmp/easyrsa + PKI_DIR="/etc/openvpn/ssl" + if [ -d "$PKI_DIR" ]; then + rm -rfv "$PKI_DIR" + fi +fi \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/vpn.sh b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/vpn.sh new file mode 100644 index 0000000..e99b9b9 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/vpn.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +log() { + logger -t "OpenVpn Vpn" "$@" +} + +/etc/init.d/openvpn stop $1 +sleep 5 + diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/vpng.sh b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/vpng.sh new file mode 100644 index 0000000..8b34078 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/easyrsa/vpng.sh @@ -0,0 +1,128 @@ +#!/bin/sh +. /lib/functions.sh + +convert() { + secs=$1 + csec=$(printf "%02d:%02d:%02d" $(($secs/3600)) $(($secs%3600/60)) $(($secs%60))) +} + +clist() { + SDIR="/tmp/run" + + STAT=$SDIR"/openvpn."$1".status" + + COUNT=0 + RT=0 + TT="Virtual Address Common Name Real Address" + while read -r line; do + name="$line" + RTT=$(echo "$name" | grep "Virtual Address") + if [ ! -z "$RTT" ]; then + RT=1 + fi + RTT=$(echo "$name" | grep "GLOBAL STATS") + if [ ! -z "$RTT" ]; then + RT=0 + fi + if [ $RT = 1 ]; then + if [ $COUNT -gt 0 ]; then + vip=$(echo "$name" | cut -d, -f1) + com=$(echo "$name" | cut -d, -f2) + rel=$(echo "$name" | cut -d, -f3) + TT="$TT $vip $com $rel" + fi + let COUNT=COUNT+1 + fi + done < "$STAT" + if [ $COUNT -le 1 ]; then + TT="No clients" + COUNT=0 + else + let COUNT=COUNT-1 + fi +} + +rm -f /tmp/vpn + +vpn_instance() { + local s="$1" + echo "$s " >> /tmp/vpn + config_get config "$s" config + if [ -z $config ]; then + config_get_bool client "$s" client 0 + else + client=1 + fi + echo "$client" >> /tmp/vpn + config_get_bool enabled "$s" 'enabled' 0 + echo "$enabled" >> /tmp/vpn + + result=`ps | grep -i "/usr/sbin/openvpn --syslog openvpn($s)" | grep -v "grep" | wc -l` + if [ $result -ge 1 ] + then + echo "1" >> /tmp/vpn + else + echo "0" >> /tmp/vpn + fi + + if [ -z $config ]; then + config_get port "$s" port + if [ -z $port ]; then + echo "1194" >> /tmp/vpn + else + echo "$port" >> /tmp/vpn + fi + config_get proto "$s" proto + if [ -z $proto ]; then + echo "udp" >> /tmp/vpn + else + echo "$proto" >> /tmp/vpn + fi + else + prott=$(cat "$config" | grep -i "proto " | tr " " ",") + prot=$(echo "$prott" | cut -d, -f2) + remtt=$(cat "$config" | grep -i -m 1 "remote " | tr " " ",") + remt=$(echo "$remtt" | cut -d, -f3) + echo "$remt" >> /tmp/vpn + echo "$prot" >> /tmp/vpn + fi + if [ $client = "0" ]; then + echo "---" >> /tmp/vpn + if [ $result -ge 1 ]; then + clist $s + echo "$COUNT" >> /tmp/vpn + echo "$TT" >> /tmp/vpn + else + echo "0" >> /tmp/vpn + echo "Not running" >> /tmp/vpn + fi + else + if [ -z $config ]; then + config_get remote "$s" remote + echo "$remote" >> /tmp/vpn + else + remtt=$(cat "$config" | grep -i -m 1 "remote " | tr " " ",") + remt=$(echo "$remtt" | cut -d, -f2) + echo "$remt" >> /tmp/vpn + fi + echo "---" >> /tmp/vpn + echo "not server" >> /tmp/vpn + fi + if [ $result -ge 1 ] + then + config_get laststart "$s" laststart + CURRTIME=$(date +%s) + let upt=CURRTIME-laststart + convert $upt + upt=$csec + else + upt="---" + fi + echo "$upt" >> /tmp/vpn +} + +config_load 'openvpn' +config_foreach vpn_instance 'openvpn' + +exit 0 + diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/controller/openvpn.lua b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/controller/openvpn.lua new file mode 100644 index 0000000..80dbf89 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/controller/openvpn.lua @@ -0,0 +1,135 @@ +-- Copyright 2008 Steven Barth +-- Copyright 2008 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.openvpn", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + entry({"admin", "vpn"}, firstchild(), translate("VPN"), 30).dependent=false + entry( {"admin", "vpn", "openvpn"}, cbi("openvpn"), _(translate("OpenVPN")), 1 ) + entry( {"admin", "vpn", "openvpn-server"}, cbi("openvpn-server"), _(translate("--OpenVPN Extras")), 2 ) + + entry( {"admin", "vpn", "openvpn", "basic"}, cbi("openvpn-basic"), nil ).leaf = true + entry( {"admin", "vpn", "openvpn", "advanced"}, cbi("openvpn-advanced"), nil ).leaf = true + entry( {"admin", "vpn", "openvpn", "file"}, form("openvpn-file"), nil ).leaf = true + entry( {"admin", "vpn", "openvpn", "upload"}, call("ovpn_upload")) + end + + entry({"admin", "vpn", "vpnstatus"}, call("action_vpnstatus")) + entry({"admin", "vpn", "rsastatus"}, call("action_status")) + entry({"admin", "vpn", "rsagenerate"}, call("action_generate")) + entry({"admin", "vpn", "rsastop"}, call("action_stop")) +end + +function ovpn_upload() + local fs = require("nixio.fs") + local http = require("luci.http") + local util = require("luci.util") + local uci = require("luci.model.uci").cursor() + local upload = http.formvalue("ovpn_file") + local name = http.formvalue("instance_name2") + local file = "/etc/openvpn/" ..name.. ".ovpn" + + if name and upload then + local fp + + http.setfilehandler( + function(meta, chunk, eof) + local data = util.trim(chunk:gsub("\r\n", "\n")) .. "\n" + data = util.trim(data:gsub("[\128-\255]", "")) + + if not fp and meta and meta.name == "ovpn_file" then + fp = io.open(file, "w") + end + if fp and data then + fp:write(data) + end + if fp and eof then + fp:close() + end + end + ) + + if fs.access(file) then + if not uci:get_first("openvpn", name) then + uci:set("openvpn", name, "openvpn") + uci:set("openvpn", name, "config", file) + uci:save("openvpn") + uci:commit("openvpn") + end + end + end + http.redirect(luci.dispatcher.build_url('admin/vpn/openvpn')) +end + +function action_status() + local rv = {} + + file = io.open("/tmp/easyrsa", "r") + if file ~= nil then + rv["status"] = file:read("*line") + file:close() + else + rv["status"] = "0" + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_generate() + os.execute("/usr/lib/easyrsa/generate.sh &") +end + +function action_stop() + os.execute("/usr/lib/easyrsa/stop.sh") +end + +function action_vpnstatus() + local rv ={} + + os.execute("/usr/lib/easyrsa/vpng.sh") + local file = io.open("/tmp/vpn", "r") + if file ~= nil then + i = 0 + name = file:read("*line") + while name ~= nil do + vpntype = file:read("*line") + enabled = file:read("*line") + started = file:read("*line") + port = file:read("*line") + proto = file:read("*line") + remote = file:read("*line") + clients = file:read("*line") + tooltip = file:read("*line") + laststart = file:read("*line") + rv[#rv+1] = { + name = name, + vpntype = vpntype, + enabled = enabled, + started = started, + port = port, + proto = proto, + remote = remote, + clients = clients, + tooltip = tooltip, + laststart = laststart + } + name = file:read("*line") + end + file:close() + else + rv[#rv+1] = { + enabled = "-1", + } + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-advanced.lua b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-advanced.lua new file mode 100644 index 0000000..a79288d --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-advanced.lua @@ -0,0 +1,902 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local fs = require("nixio.fs") + +local knownParams = { + -- + --Widget + -- Name + -- Default(s) + -- Description + -- Option(s) + + { "Service", { + -- initialisation and daemon options + { ListValue, + "verb", + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, + translate("Set output verbosity") }, + { Flag, + "mlock", + 0, + translate("Disable Paging") }, + { Flag, + "disable_occ", + 0, + translate("Disable options consistency check") }, + -- { Value, + -- "user", + -- "root", + -- translate("Set UID to user") }, + -- { Value, + -- "group", + -- "root", + -- translate("Set GID to group") }, + { Value, + "cd", + "/etc/openvpn", + translate("Change to directory before initialization") }, + { Value, + "chroot", + "/var/run", + translate("Chroot to directory after initialization") }, + -- { Value, + -- "daemon", + -- "Instance-Name", + -- translate("Daemonize after initialization") }, + -- { Value, + -- "syslog", + -- "Instance-Name", + -- translate("Output to syslog and do not daemonize") }, + { Flag, + "passtos", + 0, + translate("TOS passthrough (applies to IPv4 only)") }, + -- { Value, + -- "inetd", + -- "nowait Instance-Name", + -- translate("Run as an inetd or xinetd server") }, + { Value, + "log", + "/var/log/openvpn.log", + translate("Write log to file") }, + { Value, + "log_append", + "/var/log/openvpn.log", + translate("Append log to file") }, + { Flag, + "suppress_timestamps", + 0, + translate("Don't log timestamps") }, + -- { Value, + -- "writepid", + -- "/var/run/openvpn.pid", + -- translate("Write process ID to file") }, + { Value, + "nice", + 0, + translate("Change process priority") }, + { Flag, + "fast_io", + 0, + translate("Optimize TUN/TAP/UDP writes") }, + { Value, + "echo", + "some params echoed to log", + translate("Echo parameters to log") }, + { ListValue, + "remap_usr1", + { "SIGHUP", "SIGTERM" }, + translate("Remap SIGUSR1 signals") }, + { Value, + "status", + "/var/run/openvpn.status 5", + translate("Write status to file every n seconds") }, + { Value, + "status_version", + { 1, 2 }, + translate("Status file format version") }, -- status + { Value, + "mute", + 5, + translate("Limit repeated log messages") }, + { Value, + "up", + "/usr/bin/ovpn-up", + translate("Shell cmd to execute after tun device open") }, + { Value, + "up_delay", + 5, + translate("Delay tun/tap open and up script execution") }, + { Value, + "down", + "/usr/bin/ovpn-down", + translate("Shell cmd to run after tun device close") }, + { Flag, + "down_pre", + 0, + translate("Call down cmd/script before TUN/TAP close") }, + { Flag, + "up_restart", + 0, + translate("Run up/down scripts for all restarts") }, + { Value, + "route_up", + "/usr/bin/ovpn-routeup", + translate("Execute shell cmd after routes are added") }, + { Value, + "ipchange", + "/usr/bin/ovpn-ipchange", + translate("Execute shell command on remote ip change"), + { mode="p2p" } }, + { DynamicList, + "setenv", + { "VAR1 value1", "VAR2 value2" }, + translate("Pass environment variables to script") }, + { Value, + "tls_verify", + "/usr/bin/ovpn-tlsverify", + translate("Shell command to verify X509 name") }, + { Value, + "client_connect", + "/usr/bin/ovpn-clientconnect", + translate("Run script cmd on client connection") }, + { Value, + "client_disconnect", + "/usr/bin/ovpn-clientdisconnect", + translate("Run script cmd on client disconnection") }, + { Value, + "learn_address", + "/usr/bin/ovpn-learnaddress", + translate("Executed in server mode whenever an IPv4 address/route or MAC address is added to OpenVPN's internal routing table") }, + { Value, + "auth_user_pass_verify", + "/usr/bin/ovpn-userpass via-env", + translate("Executed in server mode on new client connections, when the client is still untrusted") }, + { ListValue, + "script_security", + { 0, 1, 2, 3 }, + translate("Policy level over usage of external programs and scripts") }, + { ListValue, + "compress", + { "lzo", "lz4" }, + translate("Enable a compression algorithm") }, + } }, + + { "Networking", { + -- socket config + { ListValue, + "mode", + { "p2p", "server" }, + translate("Major mode") }, + { Value, + "local", + "0.0.0.0", + translate("Local host name or ip address") }, + { Value, + "port", + 1194, + translate("TCP/UDP port # for both local and remote") }, + { Value, + "lport", + 1194, + translate("TCP/UDP port # for local (default=1194)") }, + { Value, + "rport", + 1194, + translate("TCP/UDP port # for remote (default=1194)") }, + { Flag, + "float", + 0, + translate("Allow remote to change its IP or port") }, + { Flag, + "nobind", + 0, + translate("Do not bind to local address and port") }, + { Value, + "dev", + "tun0", + translate("tun/tap device") }, + { ListValue, + "dev_type", + { "tun", "tap" }, + translate("Type of used device") }, + { Value, + "dev_node", + "/dev/net/tun", + translate("Use tun/tap device node") }, + { Value, + "ifconfig", + "10.200.200.3 10.200.200.1", + translate("Set tun/tap adapter parameters") }, + { Flag, + "ifconfig_noexec", + 0, + translate("Don't actually execute ifconfig") }, + { Flag, + "ifconfig_nowarn", + 0, + translate("Don't warn on ifconfig inconsistencies") }, + { DynamicList, + "route", + "10.123.0.0 255.255.0.0", + translate("Add route after establishing connection") }, + { Value, + "route_gateway", + "10.234.1.1", + translate("Specify a default gateway for routes") }, + { Value, + "route_delay", + 0, + translate("Delay n seconds after connection") }, + { Flag, + "route_noexec", + 0, + translate("Don't add routes automatically") }, + { Flag, + "route_nopull", + 0, + translate("Don't pull routes automatically") }, + { Flag, + "allow_recursive_routing", + 0, + translate("Don't drop incoming tun packets with same destination as host") }, + { ListValue, + "mtu_disc", + { "yes", "maybe", "no" }, + translate("Enable Path MTU discovery") }, + { Flag, + "mtu_test", + 0, + translate("Empirically measure MTU") }, + { ListValue, + "comp_lzo", + { "yes", "no", "adaptive" }, + translate("Use fast LZO compression") }, + { Flag, + "comp_noadapt", + 0, + translate("Don't use adaptive lzo compression"), + { comp_lzo=1 } }, + { Value, + "link_mtu", + 1500, + translate("Set TCP/UDP MTU") }, + { Value, + "tun_mtu", + 1500, + translate("Set tun/tap device MTU") }, + { Value, + "tun_mtu_extra", + 1500, + translate("Set tun/tap device overhead") }, + { Value, + "fragment", + 1500, + translate("Enable internal datagram fragmentation"), + { proto="udp" } }, + { Value, + "mssfix", + 1500, + translate("Set upper bound on TCP MSS"), + { proto="udp" } }, + { Value, + "sndbuf", + 65536, + translate("Set the TCP/UDP send buffer size") }, + { Value, + "rcvbuf", + 65536, + translate("Set the TCP/UDP receive buffer size") }, + { Value, + "txqueuelen", + 100, + translate("Set tun/tap TX queue length") }, + { Value, + "shaper", + 10240, + translate("Shaping for peer bandwidth") }, + { Value, + "inactive", + 240, + translate("tun/tap inactivity timeout") }, + { Value, + "keepalive", + "10 60", + translate("Helper directive to simplify the expression of --ping and --ping-restart in server mode configurations") }, + { Value, + "ping", + 30, + translate("Ping remote every n seconds over TCP/UDP port") }, + { Value, + "ping_exit", + 120, + translate("Remote ping timeout") }, + { Value, + "ping_restart", + 60, + translate("Restart after remote ping timeout") }, + { Flag, + "ping_timer_rem", + 0, + translate("Only process ping timeouts if routes exist") }, + { Flag, + "persist_tun", + 0, + translate("Keep tun/tap device open on restart") }, + { Flag, + "persist_key", + 0, + translate("Don't re-read key on restart") }, + { Flag, + "persist_local_ip", + 0, + translate("Keep local IP address on restart") }, + { Flag, + "persist_remote_ip", + 0, + translate("Keep remote IP address on restart") }, + -- management channel + { Value, + "management", + "127.0.0.1 31194 /etc/openvpn/mngmt-pwds", + translate("Enable management interface on IP port") }, + -- management + { Flag, + "management_query_passwords", + 0, + translate("Query management channel for private key") }, + -- management + { Flag, + "management_hold", + 0, + translate("Start OpenVPN in a hibernating state") }, + -- management + { Value, + "management_log_cache", + 100, + translate("Number of lines for log file history") }, + { ListValue, + "topology", + { "net30", "p2p", "subnet" }, + translate("'net30', 'p2p', or 'subnet'"), + {dev_type="tun" } }, + } }, + + { "VPN", { + { Value, + "server", + "10.200.200.0 255.255.255.0", + translate("Configure server mode"), + { client="0" }, { client="" } }, + { Value, + "server_bridge", + "10.200.200.1 255.255.255.0 10.200.200.200 10.200.200.250", + translate("Configure server bridge"), + { client="0" }, { client="" } }, + { DynamicList, + "push", + { "redirect-gateway", "comp-lzo" }, + translate("Push options to peer"), + { client="0" }, { client="" } }, + { Flag, + "push_reset", + 0, + translate("Don't inherit global push options"), + { client="0" }, { client="" } }, + { Flag, + "disable", + 0, + translate("Client is disabled"), + { client="0" }, { client="" } }, + { Value, + "ifconfig_pool", + "10.200.200.100 10.200.200.150 255.255.255.0", + translate("Set aside a pool of subnets"), + { client="0" }, { client="" } }, + { Value, + "ifconfig_pool_persist", + "/etc/openvpn/ipp.txt 600", + translate("Persist/unpersist ifconfig-pool"), + { client="0" }, { client="" } }, + { Value, + "ifconfig_push", + "10.200.200.1 255.255.255.255", + translate("Push an ifconfig option to remote"), + { client="0" }, { client="" } }, + { Value, + "iroute", + "10.200.200.0 255.255.255.0", + translate("Route subnet to client"), + { client="0" }, { client="" } }, + { Flag, + "client_to_client", + 0, + translate("Allow client-to-client traffic"), + { client="0" }, { client="" } }, + { Flag, + "duplicate_cn", + 0, + translate("Allow multiple clients with same certificate"), + { client="0" }, { client="" } }, + { Value, + "client_config_dir", + "/etc/openvpn/ccd", + translate("Directory for custom client config files"), + { client="0" }, { client="" } }, + { Flag, + "ccd_exclusive", + 0, + translate("Refuse connection if no custom client config"), + { client="0" }, { client="" } }, + { Value, + "tmp_dir", + "/var/run/openvpn", + translate("Temporary directory for client-connect return file"), + { client="0" }, { client="" } }, + { Value, + "hash_size", + "256 256", + translate("Set size of real and virtual address hash tables"), + { client="0" }, { client="" } }, + { Value, + "bcast_buffers", + 256, + translate("Number of allocated broadcast buffers"), + { client="0" }, { client="" } }, + { Value, + "tcp_queue_limit", + 64, + translate("Maximum number of queued TCP output packets"), + { client="0" }, { client="" } }, + { Value, + "max_clients", + 10, + translate("Allowed maximum of connected clients"), + { client="0" }, { client="" } }, + { Value, + "max_routes_per_client", + 256, + translate("Allowed maximum of internal"), + { client="0" }, { client="" } }, + { Value, + "connect_freq", + "3 10", + translate("Allowed maximum of new connections"), + { client="0" }, { client="" } }, + { Flag, + "username_as_common_name", + 0, + translate("Use username as common name"), + { client="0" }, { client="" } }, + { Flag, + "client", + 0, + translate("Configure client mode") }, + { Flag, + "pull", + 0, + translate("Accept options pushed from server"), + { client="1" } }, + { FileUpload, + "auth_user_pass", + "/etc/openvpn/userpass.txt", + translate("Authenticate using username/password"), + { client="1" } }, + { ListValue, + "auth_retry", + { "none", "nointeract", "interact" }, + translate("Handling of authentication failures"), + { client="1" } }, + { Value, + "explicit_exit_notify", + 1, + translate("Send notification to peer on disconnect"), + { client="1" } }, + { DynamicList, + "remote", + "1.2.3.4", + translate("Remote host name or ip address") }, + { Flag, + "remote_random", + 0, + translate("Randomly choose remote server"), + { client="1" } }, + { ListValue, + "proto", + { "udp", "tcp-client", "tcp-server" }, + translate("Use protocol"), + { client="1" } }, + { Value, + "connect_retry", + 5, + translate("Connection retry interval"), + { proto="tcp-client" }, { client="1" } }, + { Value, + "http_proxy", + "192.168.1.100 8080", + translate("Connect to remote host through an HTTP proxy"), + { client="1" } }, + { Flag, + "http_proxy_retry", + 0, + translate("Retry indefinitely on HTTP proxy errors"), + { client="1" } }, + { Value, + "http_proxy_timeout", + 5, + translate("Proxy timeout in seconds"), + { client="1" } }, + { DynamicList, + "http_proxy_option", + { "VERSION 1.0", "AGENT OpenVPN/2.0.9" }, + translate("Set extended HTTP proxy options"), + { client="1" } }, + { Value, + "socks_proxy", + "192.168.1.200 1080", + translate("Connect through Socks5 proxy"), + { client="1" } }, + -- client && socks_proxy + { Value, + "socks_proxy_retry", + 5, + translate("Retry indefinitely on Socks proxy errors"), + { client="1" } }, + { Value, + "resolv_retry", + "infinite", + translate("If hostname resolve fails, retry"), + { client="1" } }, + { ListValue, + "redirect_gateway", + { "", "local", "def1", "local def1" }, + translate("Automatically redirect default route"), + { client="1" } }, + { Value, + "verify_client_cert", + { "none", "optional", "require" }, + translate("Specify whether the client is required to supply a valid certificate") }, + } }, + + { "Cryptography", { + { FileUpload, + "secret", + "/etc/openvpn/secret.key", + translate("Enable Static Key encryption mode (non-TLS)") }, + -- parse + { Value, + "auth", + "SHA1", + translate("HMAC authentication for packets") }, + -- parse + { Value, + "cipher", + { + "AES-128-CBC", + "AES-128-CFB", + "AES-128-CFB1", + "AES-128-CFB8", + "AES-128-GCM", + "AES-128-OFB", + "AES-192-CBC", + "AES-192-CFB", + "AES-192-CFB1", + "AES-192-CFB8", + "AES-192-GCM", + "AES-192-OFB", + "AES-256-CBC", + "AES-256-CFB", + "AES-256-CFB1", + "AES-256-CFB8", + "AES-256-GCM", + "AES-256-OFB", + "BF-CBC", + "BF-CFB", + "BF-OFB", + "CAST5-CBC", + "CAST5-CFB", + "CAST5-OFB", + "DES-CBC", + "DES-CFB", + "DES-CFB1", + "DES-CFB8", + "DES-EDE-CBC", + "DES-EDE-CFB", + "DES-EDE-OFB", + "DES-EDE3-CBC", + "DES-EDE3-CFB", + "DES-EDE3-CFB1", + "DES-EDE3-CFB8", + "DES-EDE3-OFB", + "DES-OFB", + "DESX-CBC", + "RC2-40-CBC", + "RC2-64-CBC", + "RC2-CBC", + "RC2-CFB", + "RC2-OFB" + }, + translate("Encryption cipher for packets") }, + -- parse + { Value, + "keysize", + 1024, + translate("Size of cipher key") }, + -- parse + { Value, + "engine", + "dynamic", + translate("Enable OpenSSL hardware crypto engines") }, + { Value, + "replay_window", + "64 15", + translate("Replay protection sliding window size") }, + { Flag, + "mute_replay_warnings", + 0, + translate("Silence the output of replay warnings") }, + { Value, + "replay_persist", + "/var/run/openvpn-replay-state", + translate("Persist replay-protection state") }, + { Flag, + "tls_server", + 0, + translate("Enable TLS and assume server role"), + { tls_client="" }, { tls_client="0" } }, + { Flag, + "tls_client", + 0, + translate("Enable TLS and assume client role"), + { tls_server="" }, { tls_server="0" } }, + { FileUpload, + "ca", + "/etc/easy-rsa/keys/ca.crt", + translate("Certificate authority") }, + { FileUpload, + "dh", + "/etc/easy-rsa/keys/dh1024.pem", + translate("Diffie Hellman parameters") }, + { FileUpload, + "cert", + "/etc/easy-rsa/keys/some-client.crt", + translate("Local certificate") }, + { FileUpload, + "key", + "/etc/easy-rsa/keys/some-client.key", + translate("Local private key") }, + { FileUpload, + "pkcs12", + "/etc/easy-rsa/keys/some-client.pk12", + translate("PKCS#12 file containing keys") }, + { ListValue, + "key_method", + { 1, 2 }, + translate("Enable TLS and assume client role") }, + { DynamicList, + "tls_cipher", + { + "DHE-RSA-AES256-SHA", + "DHE-DSS-AES256-SHA", + "AES256-SHA", + "EDH-RSA-DES-CBC3-SHA", + "EDH-DSS-DES-CBC3-SHA", + "DES-CBC3-SHA", + "DHE-RSA-AES128-SHA", + "DHE-DSS-AES128-SHA", + "AES128-SHA", + "RC4-SHA", + "RC4-MD5", + "EDH-RSA-DES-CBC-SHA", + "EDH-DSS-DES-CBC-SHA", + "DES-CBC-SHA", + "EXP-EDH-RSA-DES-CBC-SHA", + "EXP-EDH-DSS-DES-CBC-SHA", + "EXP-DES-CBC-SHA", + "EXP-RC2-CBC-MD5", + "EXP-RC4-MD5" + }, + translate("TLS cipher") }, + { DynamicList, + "tls_ciphersuites", + { + "TLS_AES_256_GCM_SHA384", + "TLS_AES_128_GCM_SHA256", + "TLS_CHACHA20_POLY1305_SHA256" + }, + translate("TLS 1.3 or newer cipher") }, + { Value, + "tls_timeout", + 2, + translate("Retransmit timeout on TLS control channel") }, + { Value, + "reneg_bytes", + 1024, + translate("Renegotiate data chan. key after bytes") }, + { Value, + "reneg_pkts", + 100, + translate("Renegotiate data chan. key after packets") }, + { Value, + "reneg_sec", + 3600, + translate("Renegotiate data chan. key after seconds") }, + { Value, + "hand_window", + 60, + translate("Timeframe for key exchange") }, + { Value, + "tran_window", + 3600, + translate("Key transition window") }, + { Flag, + "single_session", + 0, + translate("Allow only one session") }, + { Flag, + "tls_exit", + 0, + translate("Exit on TLS negotiation failure") }, + { Value, + "tls_auth", + "/etc/openvpn/tlsauth.key", + translate("Additional authentication over TLS") }, + { Value, + "tls_crypt", + "/etc/openvpn/tlscrypt.key", + translate("Encrypt and authenticate all control channel packets with the key") }, + -- { Value, + -- "askpass", + -- "[file]", + -- translate("Get PEM password from controlling tty before we daemonize") }, + { Flag, + "auth_nocache", + 0, + translate("Don't cache --askpass or --auth-user-pass passwords") }, + { Value, + "tls_remote", + "remote_x509_name", + translate("Only accept connections from given X509 name") }, + { ListValue, + "ns_cert_type", + { "client", "server" }, + translate("Require explicit designation on certificate") }, + { ListValue, + "remote_cert_tls", + { "client", "server" }, + translate("Require explicit key usage on certificate") }, + { Value, + "crl_verify", + "/etc/easy-rsa/keys/crl.pem", + translate("Check peer certificate against a CRL") }, + { Value, + "tls_version_min", + "1.0", + translate("The lowest supported TLS version") }, + { Value, + "tls_version_max", + "1.2", + translate("The highest supported TLS version") }, + { ListValue, + "key_direction", + { 0, 1 }, + translate("The key direction for 'tls-auth' and 'secret' options") }, + { Flag, + "ncp_disable", + 0, + translate("This completely disables cipher negotiation") }, + { Value, + "ncp_ciphers", + "AES-256-GCM:AES-128-GCM", + translate("Restrict the allowed ciphers to be negotiated") }, + } } +} + + +local cts = { } +local params = { } + +local m = Map("openvpn") +m.redirect = luci.dispatcher.build_url("admin", "vpn", "openvpn") +m.apply_on_parse = true + +local p = m:section( SimpleSection ) +p.template = "openvpn/pageswitch" +p.mode = "advanced" +p.instance = arg[1] +p.category = arg[2] or "Service" + +for _, c in ipairs(knownParams) do + cts[#cts+1] = c[1] + if c[1] == p.category then params = c[2] end +end + +p.categories = cts + + +local s = m:section( + NamedSection, arg[1], "openvpn", + translate("%s" % arg[2]) +) + +s.title = translate("%s" % arg[2]) +s.addremove = false +s.anonymous = true + + +for _, option in ipairs(params) do + local o = s:option( + option[1], option[2], + option[2], option[4] + ) + + o.optional = true + + if option[1] == DummyValue then + o.value = option[3] + elseif option[1] == FileUpload then + + o.initial_directory = "/etc/openvpn" + + function o.cfgvalue(self, section) + local cfg_val = AbstractValue.cfgvalue(self, section) + + if cfg_val then + return cfg_val + end + end + + function o.formvalue(self, section) + local sel_val = AbstractValue.formvalue(self, section) + local txt_val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + + if sel_val and sel_val ~= "" then + return sel_val + end + + if txt_val and txt_val ~= "" then + return txt_val + end + end + + function o.remove(self, section) + local cfg_val = AbstractValue.cfgvalue(self, section) + local txt_val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + + if cfg_val and fs.access(cfg_val) and txt_val == "" then + fs.unlink(cfg_val) + end + return AbstractValue.remove(self, section) + end + elseif option[1] == Flag then + o.default = nil + else + if option[1] == DynamicList then + function o.cfgvalue(...) + local val = AbstractValue.cfgvalue(...) + return ( val and type(val) ~= "table" ) and { val } or val + end + end + + if type(option[3]) == "table" then + if o.optional then o:value("", "-- remove --") end + for _, v in ipairs(option[3]) do + v = tostring(v) + o:value(v) + end + o.default = tostring(option[3][1]) + else + o.default = tostring(option[3]) + end + end + + for i=5,#option do + if type(option[i]) == "table" then + o:depends(option[i]) + end + end +end + +return m diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-basic.lua b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-basic.lua new file mode 100644 index 0000000..dbab780 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-basic.lua @@ -0,0 +1,196 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local fs = require("nixio.fs") + +local basicParams = { + -- + -- Widget, Name, Default(s), Description + -- + { ListValue, + "verb", + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, + translate("Set output verbosity") }, + { Value, + "nice", + 0, + translate("Change process priority") }, + { Value, + "port", + 1194, + translate("TCP/UDP port # for both local and remote") }, + { ListValue, + "dev_type", + { "tun", "tap" }, + translate("Type of used device") }, + { Value, + "ifconfig", + "10.200.200.3 10.200.200.1", + translate("Set tun/tap adapter parameters") }, + { Value, + "server", + "10.200.200.0 255.255.255.0", + translate("Configure server mode") }, + { Value, + "server_bridge", + "192.168.1.1 255.255.255.0 192.168.1.128 192.168.1.254", + translate("Configure server bridge") }, + { Flag, + "nobind", + 0, + translate("Do not bind to local address and port") }, + { ListValue, + "comp_lzo", + {"yes","no","adaptive"}, + translate("Use fast LZO compression") }, + { Value, + "keepalive", + "10 60", + translate("Helper directive to simplify the expression of --ping and --ping-restart in server mode configurations") }, + { Flag, + "client", + 0, + translate("Configure client mode") }, + { Flag, + "client_to_client", + 0, + translate("Allow client-to-client traffic") }, + { DynamicList, + "remote", + "vpnserver.example.org", + translate("Remote host name or ip address") }, + { FileUpload, + "secret", + "/etc/openvpn/secret.key", + translate("Enable Static Key encryption mode (non-TLS)") }, + { ListValue, + "key_direction", + { 0, 1 }, + translate("The key direction for 'tls-auth' and 'secret' options") }, + { FileUpload, + "pkcs12", + "/etc/easy-rsa/keys/some-client.pk12", + translate("PKCS#12 file containing keys") }, + { FileUpload, + "ca", + "/etc/easy-rsa/keys/ca.crt", + translate("Certificate authority") }, + { FileUpload, + "dh", + "/etc/easy-rsa/keys/dh1024.pem", + translate("Diffie Hellman parameters") }, + { FileUpload, + "cert", + "/etc/easy-rsa/keys/some-client.crt", + translate("Local certificate") }, + { FileUpload, + "key", + "/etc/easy-rsa/keys/some-client.key", + translate("Local private key") }, + { FileUpload, + "auth_user_pass", + "/etc/easy-rsa/keys/some-client.pass", + translate("Password file") }, +} + +local has_ipv6 = fs.access("/proc/net/ipv6_route") +if has_ipv6 then + table.insert( basicParams, { ListValue, + "proto", + { "udp", "tcp-client", "tcp-server", "udp4", "tcp4-client", "tcp4-server","udp6", "tcp6-client", "tcp6-server" }, + translate("Use protocol") + }) +else + table.insert( basicParams, { ListValue, + "proto", + { "udp", "tcp-client", "tcp-server" }, + translate("Use protocol") + }) +end + +local m = Map("openvpn") +m.redirect = luci.dispatcher.build_url("admin", "vpn", "openvpn") +m.apply_on_parse = true + +local p = m:section( SimpleSection ) +p.template = "openvpn/pageswitch" +p.mode = "basic" +p.instance = arg[1] + + +local s = m:section( NamedSection, arg[1], "openvpn" ) + +for _, option in ipairs(basicParams) do + local o = s:option( + option[1], option[2], + option[2], option[4] + ) + + o.optional = true + + if option[1] == DummyValue then + o.value = option[3] + elseif option[1] == FileUpload then + + o.initial_directory = "/etc/openvpn" + + function o.cfgvalue(self, section) + local cfg_val = AbstractValue.cfgvalue(self, section) + + if cfg_val then + return cfg_val + end + end + + function o.formvalue(self, section) + local sel_val = AbstractValue.formvalue(self, section) + local txt_val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + + if sel_val and sel_val ~= "" then + return sel_val + end + + if txt_val and txt_val ~= "" then + return txt_val + end + end + + function o.remove(self, section) + local cfg_val = AbstractValue.cfgvalue(self, section) + local txt_val = luci.http.formvalue("cbid."..self.map.config.."."..section.."."..self.option..".textbox") + + if cfg_val and fs.access(cfg_val) and txt_val == "" then + fs.unlink(cfg_val) + end + return AbstractValue.remove(self, section) + end + elseif option[1] == Flag then + o.default = nil + else + if option[1] == DynamicList then + function o.cfgvalue(...) + local val = AbstractValue.cfgvalue(...) + return ( val and type(val) ~= "table" ) and { val } or val + end + end + + if type(option[3]) == "table" then + if o.optional then o:value("", "-- remove --") end + for _, v in ipairs(option[3]) do + v = tostring(v) + o:value(v) + end + o.default = tostring(option[3][1]) + else + o.default = tostring(option[3]) + end + end + + for i=5,#option do + if type(option[i]) == "table" then + o:depends(option[i]) + end + end +end + +return m diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-file.lua b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-file.lua new file mode 100644 index 0000000..9d50601 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-file.lua @@ -0,0 +1,82 @@ +-- Licensed to the public under the Apache License 2.0. + +local ip = require("luci.ip") +local fs = require("nixio.fs") +local util = require("luci.util") +local uci = require("luci.model.uci").cursor() +local cfg_file = uci:get("openvpn", arg[1], "config") +local auth_file = cfg_file:match("(.+)%..+").. ".auth" + +local m = Map("openvpn") + +local p = m:section( SimpleSection ) +p.template = "openvpn/pageswitch" +p.mode = "file" +p.instance = arg[1] + +if not cfg_file or not fs.access(cfg_file) then + local f = SimpleForm("error", nil, translatef("The OVPN config file (%s) could not be found, please check your configuration.", cfg_file or "n/a")) + f:append(Template("openvpn/ovpn_css")) + f.reset = false + f.submit = false + return m, f +end + +if fs.stat(cfg_file).size >= 102400 then + f = SimpleForm("error", nil, + translatef("The size of the OVPN config file (%s) is too large for online editing in LuCI (≥ 100 KB). ", cfg_file) + .. translate("Please edit this file directly in a terminal session.")) + f:append(Template("openvpn/ovpn_css")) + f.reset = false + f.submit = false + return m, f +end + +f = SimpleForm("cfg", nil) +f:append(Template("openvpn/ovpn_css")) +f.submit = translate("Save") +f.reset = false + +s = f:section(SimpleSection, nil, translatef("Section to modify the OVPN config file (%s)", cfg_file)) +file = s:option(TextValue, "data1") +file.datatype = "string" +file.rows = 20 + +function file.cfgvalue() + return fs.readfile(cfg_file) or "" +end + +function file.write(self, section, data1) + return fs.writefile(cfg_file, "\n" .. util.trim(data1:gsub("\r\n", "\n")) .. "\n") +end + +function file.remove(self, section, value) + return fs.writefile(cfg_file, "") +end + +function s.handle(self, state, data1) + return true +end + +s = f:section(SimpleSection, nil, translatef("Section to add an optional 'auth-user-pass' file with your credentials (%s)", auth_file)) +file = s:option(TextValue, "data2") +file.datatype = "string" +file.rows = 5 + +function file.cfgvalue() + return fs.readfile(auth_file) or "" +end + +function file.write(self, section, data2) + return fs.writefile(auth_file, util.trim(data2:gsub("\r\n", "\n")) .. "\n") +end + +function file.remove(self, section, value) + return fs.writefile(auth_file, "") +end + +function s.handle(self, state, data2) + return true +end + +return m, f diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-server.lua b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-server.lua new file mode 100644 index 0000000..88c8888 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn-server.lua @@ -0,0 +1,86 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local fs = require "nixio.fs" +local sys = require "luci.sys" +local uci = require "luci.model.uci".cursor() + +local m = Map("openvpn", translate("OpenVPN Extras"), translate("Extra Settings for an OpenVPN Client or Server")) + +m.on_after_save = function(self) + luci.sys.call("/usr/lib/easyrsa/firewall.sh &") + luci.sys.call("/usr/lib/easyrsa/dns.sh &") +end + +gw = m:section(TypedSection, "settings", translate("Advanced Extras")) +gw.anonymous = true +gw:tab("default", translate("Custom Firewall Settings")) +gw:tab("dns", translate("Custom DNS Settings")) +gw:tab("key", translate("Key and Certificate Generation")) + +this_tab = "default" + +gw:taboption(this_tab, Flag, "vpn2lan", translate("Forward Client VPN to LAN"), translate("(Client) Allow clients behind the VPN server to connect to computers within your LAN") ) +gw:taboption(this_tab, Flag, "vpns2lan", translate("Forward Server VPN to LAN"), translate("(Server) Allow clients behind the VPN server to connect to computers within your LAN") ) +gw:taboption(this_tab, Flag, "vpn2wan", translate("Forward Server VPN to WAN"), translate("(Server) Allow clients to connect to the internet (WAN) through the tunnel") ) + +this_tab = "dns" + +gw:taboption(this_tab, Flag, "lanopendns", translate("LAN DNS using OpenDNS"), translate("Fixed DNS on LAN interface using OpenDNS") ) +gw:taboption(this_tab, Flag, "langoogle", translate("LAN DNS using Google"), translate("Fixed DNS on LAN interface using Google") ) +gw:taboption(this_tab, Flag, "wanopendns", translate("WAN DNS using OpenDNS"), translate("Fixed DNS on WAN interface using OpenDNS") ) +gw:taboption(this_tab, Flag, "wangoogle", translate("WAN DNS using Google"), translate("Fixed DNS on WAN interface using Google") ) + +this_tab = "key" + +country = gw:taboption(this_tab, Value, "country", translate("Country Name :"), translate("2 letter country abbreviation")); +country.optional=false; +country.rmempty = true; +country.default="CA" +country.datatype = "rangelength(2, 2)" + +city = gw:taboption(this_tab, Value, "city", translate("City Name :")); +city.optional=false; +city.rmempty = true; +city.default="Abbotsford" +city.datatype = "minlength(2)" + +organ = gw:taboption(this_tab, Value, "organ", translate("Organization Name :"), translate("name will appear on certs and keys")); +organ.optional=false; +organ.rmempty = true; +organ.default="ROOter" +organ.datatype = "minlength(2)" + +comm = gw:taboption(this_tab, Value, "comm", translate("Common Name :"), translate("(Optional) Common Name of Organization")); +comm.optional=true; +comm.rmempty = true; + +unit = gw:taboption(this_tab, Value, "unit", translate("Section Name :"), translate("(Optional) Name of Section")); +unit.optional=true; +unit.rmempty = true; + +unstruc = gw:taboption(this_tab, Value, "unstruc", translate("Optional Organization Name :"), translate("(Optional) Another Name for Organization")); +unstruc.optional=true; +unstruc.rmempty = true; + +email = gw:taboption(this_tab, Value, "email", translate("Email Address :"), translate("(Optional) Email Address")); +unit.optional=true; +unit.rmempty = true; + +days = gw:taboption(this_tab, Value, "days", translate("Days to certify for :"), translate("number of days certs and keys are valid")); +days.optional=false; +days.rmempty = true; +days.default="3650" +days.datatype = "min(1)" + +clnt = gw:taboption(this_tab, Value, "nclient", translate("Number of Clients :"), translate("number of clients to generate certs and keys for")); +clnt.optional=false; +clnt.rmempty = true; +clnt.default="1" +clnt.datatype = "min(1)" + +sx = gw:taboption(this_tab, Value, "_dmy1", translate(" ")) +sx.template = "easyrsa/easyrsa" + + +return m diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn.lua b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn.lua new file mode 100644 index 0000000..b79df8b --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/model/cbi/openvpn.lua @@ -0,0 +1,179 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. + +local fs = require "nixio.fs" +local sys = require "luci.sys" +local uci = require "luci.model.uci".cursor() +local testfullps = sys.exec("ps --help 2>&1 | grep BusyBox") --check which ps do we have +local psstring = (string.len(testfullps)>0) and "ps w" or "ps axfw" --set command we use to get pid + +local m = Map("openvpn", translate("OpenVPN")) +local s = m:section( TypedSection, "openvpn", translate("OpenVPN instances"), translate("Below is a list of configured OpenVPN instances and their current state") ) +s.template = "cbi/tblsection" +s.template_addremove = "openvpn/cbi-select-input-add" +s.addremove = true +s.add_select_options = { } + +local cfg = s:option(DummyValue, "config") +function cfg.cfgvalue(self, section) + local file_cfg = self.map:get(section, "config") + if file_cfg then + s.extedit = luci.dispatcher.build_url("admin", "vpn", "openvpn", "file", "%s") + else + s.extedit = luci.dispatcher.build_url("admin", "vpn", "openvpn", "basic", "%s") + end +end + +uci:load("openvpn_recipes") +uci:foreach( "openvpn_recipes", "openvpn_recipe", + function(section) + s.add_select_options[section['.name']] = + section['_description'] or section['.name'] + end +) + +function s.getPID(section) -- Universal function which returns valid pid # or nil + local pid = sys.exec("%s | grep -w '[o]penvpn(%s)'" % { psstring, section }) + if pid and #pid > 0 then + return tonumber(pid:match("^%s*(%d+)")) + else + return nil + end +end + +function s.parse(self, section) + local recipe = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".select" + ) + + if recipe and not s.add_select_options[recipe] then + self.invalid_cts = true + else + TypedSection.parse( self, section ) + end +end + +function s.create(self, name) + local recipe = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".select" + ) + local name = luci.http.formvalue( + luci.cbi.CREATE_PREFIX .. self.config .. "." .. + self.sectiontype .. ".text" + ) + if #name > 3 and not name:match("[^a-zA-Z0-9_]") then + local s = uci:section("openvpn", "openvpn", name) + if s then + local options = uci:get_all("openvpn_recipes", recipe) + for k, v in pairs(options) do + if k ~= "_role" and k ~= "_description" then + if type(v) == "boolean" then + v = v and "1" or "0" + end + uci:set("openvpn", name, k, v) + end + end + uci:save("openvpn") + uci:commit("openvpn") + if extedit then + luci.http.redirect( self.extedit:format(name) ) + end + end + elseif #name > 0 then + self.invalid_cts = true + end + return 0 +end + +function s.remove(self, name) + local cfg_file = "/etc/openvpn/" ..name.. ".ovpn" + local auth_file = "/etc/openvpn/" ..name.. ".auth" + if fs.access(cfg_file) then + fs.unlink(cfg_file) + end + if fs.access(auth_file) then + fs.unlink(auth_file) + end + uci:delete("openvpn", name) + uci:save("openvpn") + uci:commit("openvpn") +end + +s:option( Flag, "enabled", translate("Enabled") ) +s:option( Flag, "bootstart", translate("Start on Bootup") ) + +local active = s:option( DummyValue, "_active", translate("Started") ) +function active.cfgvalue(self, section) + local pid = s.getPID(section) + if pid ~= nil then + return (sys.process.signal(pid, 0)) + and translatef("yes (%i)", pid) + or translate("no") + end + return translate("no") +end + +local updown = s:option( Button, "_updown", translate("Start/Stop") ) +updown._state = false +updown.redirect = luci.dispatcher.build_url( + "admin", "vpn", "openvpn" +) +function updown.cbid(self, section) + local pid = s.getPID(section) + self._state = pid ~= nil and sys.process.signal(pid, 0) + self.option = self._state and "stop" or "start" + return AbstractValue.cbid(self, section) +end +function updown.cfgvalue(self, section) + self.title = self._state and "stop" or "start" + self.inputstyle = self._state and "reset" or "reload" +end +function updown.write(self, section, value) + if self.option == "stop" then + --sys.call("/etc/init.d/openvpn stop %s" % section) + sys.call("/usr/lib/easyrsa/vpn.sh %s" % section) + else + sys.call("/etc/init.d/openvpn start %s" % section) + end + luci.http.redirect( self.redirect ) +end + +local port = s:option( DummyValue, "port", translate("Port") ) +function port.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if not val then + local file_cfg = self.map:get(section, "config") + if file_cfg and fs.access(file_cfg) then + val = sys.exec("awk '{if(match(tolower($1),/^port$/)&&match($2,/[0-9]+/)){cnt++;printf $2;exit}}END{if(cnt==0)printf \"-\"}' " ..file_cfg) + if val == "-" then + val = sys.exec("awk '{if(match(tolower($1),/^remote$/)&&match($3,/[0-9]+/)){cnt++;printf $3;exit}}END{if(cnt==0)printf \"-\"}' " ..file_cfg) + end + end + end + return val or "-" +end + +local proto = s:option( DummyValue, "proto", translate("Protocol") ) +function proto.cfgvalue(self, section) + local val = AbstractValue.cfgvalue(self, section) + if not val then + local file_cfg = self.map:get(section, "config") + if file_cfg and fs.access(file_cfg) then + val = sys.exec("awk '{if(match(tolower($1),/^proto$/)&&match(tolower($2),/^udp[46]*$|^tcp[46]*-server$|^tcp[46]*-client$/)){cnt++;printf tolower($2);exit}}END{if(cnt==0)printf \"-\"}' " ..file_cfg) + if val == "-" then + val = sys.exec("awk '{if(match(tolower($1),/^remote$/)&&match(tolower($4),/^udp[46]*$|^tcp[46]*-server$|^tcp[46]*-client$/)){cnt++;printf $4;exit}}END{if(cnt==0)printf \"-\"}' " ..file_cfg) + end + end + end + return val or "-" +end + +function m.on_after_apply(self,map) + --sys.call('/etc/init.d/openvpn reload') +end + +m:section(SimpleSection).template = "openvpn/vpn1" + +return m diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/admin_status/index/vpn.htm b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/admin_status/index/vpn.htm new file mode 100644 index 0000000..fab323d --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/admin_status/index/vpn.htm @@ -0,0 +1 @@ +<%+openvpn/vpn1%> \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/easyrsa/easyrsa.htm b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/easyrsa/easyrsa.htm new file mode 100644 index 0000000..998a866 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/easyrsa/easyrsa.htm @@ -0,0 +1,172 @@ + + + +
                          + + + + + + + +
                             
                          +

                           

                          + + + + + + + +
                           <%:Key Generation will take 60 minutes or more so be patient.%>  
                          +

                           

                          +

                          <%:Status of Key Generation%>

                          +

                           

                          + + + + +
                          + +
                          + +

                           

                          + + + + + + + + +
                             
                          + +
                          diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/cbi-select-input-add.htm b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/cbi-select-input-add.htm new file mode 100644 index 0000000..9ca1e87 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/cbi-select-input-add.htm @@ -0,0 +1,111 @@ + + + +<%+openvpn/ovpn_css%> + +
                          +
                          +

                          <%:Template based configuration%>

                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          +
                          +
                          +

                          <%:OVPN configuration file upload%>

                          +
                          +
                          + +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          +
                          + +
                          +
                          diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/ovpn_css.htm b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/ovpn_css.htm new file mode 100644 index 0000000..55c0a54 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/ovpn_css.htm @@ -0,0 +1,38 @@ + diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/pageswitch.htm b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/pageswitch.htm new file mode 100644 index 0000000..7d88b84 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/pageswitch.htm @@ -0,0 +1,30 @@ +<%# + Copyright 2008 Steven Barth + Copyright 2008 Jo-Philipp Wich + Licensed to the public under the Apache License 2.0. +-%> + +<%+openvpn/ovpn_css%> + +
                          +

                          + <%:Overview%> » + <%=luci.i18n.translatef("Instance \"%s\"", self.instance)%> +

                          + <% if self.mode == "basic" then %> + "><%:Switch to advanced configuration%> »

                          +


                          + <% elseif self.mode == "advanced" then %> + <%:Switch to basic configuration%> »

                          +


                          + <%:Configuration category%>: + <% for i, c in ipairs(self.categories) do %> + <% if c == self.category then %> + <%=translate(c)%> + <% else %> + "><%=translate(c)%> + <% end %> + <% if next(self.categories, i) then %>|<% end %> + <% end %> + <% end %> +
                          diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/vpn1.htm b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/vpn1.htm new file mode 100644 index 0000000..1c70818 --- /dev/null +++ b/rooter/0optionalapps/luci-app-rootervpn/files/usr/lib/lua/luci/view/openvpn/vpn1.htm @@ -0,0 +1,120 @@ + + +
                          +

                          <%:OpenVPN Status%>

                          + + + + + + + + + + + + + + +
                          <%:Name%><%:Type%><%:Status%><%:Uptime%><%:Remote IP%><%:Clients%><%:Port%>

                          <%:Collecting data...%>
                          +
                          \ No newline at end of file diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/www/luci-static/resources/icons/vpn-disabled.png b/rooter/0optionalapps/luci-app-rootervpn/files/www/luci-static/resources/icons/vpn-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb0f561cf02501aa12fdf40394a522a176f2b97 GIT binary patch literal 1014 zcmVWdH}`0SOZhI*)>{(*OVf2XskIMF-;n3IYrgQc>V?00009a7bBm000XT z000XT0n*)m`~Uz0bV)=(RCwB@Ra+>mQ50VD`x(Zqlu;-qGs8JT=Shn5;I8Bn-joMP z;YE3n&VwS&$RqP2WlHBoo=9?iphVG>%Z%HMOdWJaF6B1na=z`K`De_Ka=!ki*?WEK z+iR`8_TG}0mzU+`<-NVV`}=$P5+o8ye0+RiVWCo~3@Iom*xcNN=-0FaAQYp~n39a4 z>gge~nH&xp7@(}I_qBF*7;SEj_V=Mdb#pM)2{K%yQjx~_cw=KME@%OEJ6pV|i8%*oVG35Yerz zQF}W}P0X>ajZMNN0A#qp@g2GJbXKpTBH}ooB9cNnC_Fy=Sz7XGfmU41T;TXl?T9Yr z@&uiZr6YzQWPN+f{;#jIdWl;3`N75I{09jM38tqf((9?L%$GGJR#(|4YQY48UVj%C z7qCxUz&Il#<8NdnX|+^ZN<2@&z$8psts^-(CMG7(7|cgYKSf7}4-KmW&3@(8B% z^!JtuicUaycsP9tOwKLznm^DJU0tm9!N4R;V)wj4RA3?7?e>k04Y^z{OerK1U*87< zlio99c~ybdj#r(>ZH4i|!h$gV)!6u^QH0u~UgXy(-ZP`n>-#4r{MQPpudjc6eDr8l zS5s#vt*pH1d-TNcFjZBt^Mpg@bPDN_)k=qlKRY_2l}hZM)oRVj$>DH)dbAoEKI;4a z$w_=4otYmpnaN~|jg3{QR3SQ@E+r*}=XurOAkEH_cr6QkKRWt*YwP;@S|*eIaXP=Z zw9xi8i%Y0IB1On&XAf0Xm6eqd5fQAA9!yWW)oM3NiB!VE+!YmW3u^7Yyu9q|>l+^* z_s}p269}Mz3>P?h5z^b+>j_7##;r;Q1M6PYOQSKmTsE8S;^M+=Hiw3WMny$oXmdE? zkur*ixRgp(ftng|E7-Q4pP%2{+z8`uCnxOw(r8$*J_ai^nyI^cm*K3?Cfk$vH?6KZZH@g k9v(gtf^$+*lHebJf3u{^p>{)!s{jB107*qoM6N<$f{3uxE&u=k literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/luci-app-rootervpn/files/www/luci-static/resources/icons/vpn-started.png b/rooter/0optionalapps/luci-app-rootervpn/files/www/luci-static/resources/icons/vpn-started.png new file mode 100644 index 0000000000000000000000000000000000000000..3f58ff147e996eedcdac630b5022c47905f34635 GIT binary patch literal 858 zcmV-g1Eu_lP)R#Hqb*tC^|3IO_!oogkT7Zt(*w}tvym(QM0pt@#M#g`aFJIOH z*-TAbP*BhhvaGhYwu$NG%a`JOe0-mDbabvTP#Kt-nw|#HZ{EBSVWPI-xWM4B=-9Di zRt^ph2k@yme*Czlx3~A!j~_qslV#C@1q%|KoSgREzI|Ku*|TR-@87={M3(>g^Cvq< z?CH~|(%ZIe^Rlq8H~~_N&$9pg{QMtaDdo?fKg>l%MZFAIk}A-5`$1|z$(5Cr^%uIl zprGKp-Me?Yz|2~@bZHbwJTo(M8itRqT)Cpt-``(|%|&nDz7+=1pFVx!`~CYjE4n<$ zhoz;Z-9!bQzP|p&HEY&{@bK__0r7zu?w7H#@mWw(4Gaui4-!*SQo85i;jsfGuCA_r z6QKj7r_Do0w1PMotnL9(V{pG4vrs0CkAR_3?Kdd`nqaJ)4N11OMpIN1O+FI&&b5Y^cUG?T7ayqtZ7VYYHGJ=VfgIXvs25< z%R51AVCuaCjxbPt#6aZ=518*x0X=aOls(?Pdnd>UN*xCe9<*P!Y*`d~d4>)^1?R3^ zyWB)XMBX?$I_}4(7U=l@pv;_?mp2Kdo}}b@>Cz=#kZWyhYz~u})LC%32vn8Z^Xi$y0diCm1m^d&&{WCN)JP#_GaQYBr+nFdHILPV$ROadw~VQM}}X&ezAgDD%4I4FbryCfrAcMul#OrZ?C+0 z^QJno3qh6HlP6DPi1iT&fNEN4Y3ZlPK8lNrTLcd}Y~aCz2MTlN&P{&x>XjHF3qWyX kX=!;JSb{GGr8aD80O!b@B@^pQ?EnA(07*qoM6N<$f(~MzeE@Mn=ZJqN1YLoSd90R8&;9G49&6tMBB=lZDi>039$hGyh6YPd8<`a^*@C zkpCaZ(F3~R3Np@}y0s{Axm6dmZ#D#^0Z^HBf z`Denz!~KW~IuOv%&{zjDVD;+N8-Q`amYkeyf-KL=%lj-cGSU;oe*E~c&BBEX59{jc zF822JPGezV`9ZWrAOOt3SCf*G%ub&^ox^|!aBy&Z@bK`+HZd`ohEE*}0Yl!~+S)eb zQv)hdh$&UTaRf?fgcOnkfab!}0N6*re*NMBC1)`)u}f66gz@s_%W-gvfc3^dkj=Yy z@9w3AuVD5v2?+_^qJ_!86qssdWz`8{^YQWBVS+~Xe`;HF{`~p08#itQ^7HdQQdL!5 zzz7UBhKCOy+5@ZdC}7SP#HSflaNfIj&y9kY6t+K*2yFiQS|@}jA!=_HVPP^1x! zU%q^)+uYpzf5CzUhe^=~!Z`C0s4RQ*=#ed~d;@`xA3w^0=x^V?iCn*aJrv3H|A0l; zc|k$JdpLavvhDfv=O!OMd{9J|ICt(`8nCW+AvR7xtsZA*=L%q)JVX`)mgIYZO@)t) zz_N_Bv$OLHs7#}Ff&c+?bMt;zSJxsICMKrez_wQH;|eEc>n+a literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/pingtest/Makefile b/rooter/0optionalapps/pingtest/Makefile new file mode 100644 index 0000000..0393fd7 --- /dev/null +++ b/rooter/0optionalapps/pingtest/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=pingtest +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/pingtest + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + DEPENDS:=+httping +curl + TITLE:=Added scripts for custom ping test + PKGARCH:=all +endef + +define Package/pingtest/description + Added scripts for custom ping test +endef + + +define Build/Compile +endef + +define Package/pingtest/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,pingtest)) diff --git a/rooter/0optionalapps/pingtest/files/usr/lib/custom/johns_ping.sh b/rooter/0optionalapps/pingtest/files/usr/lib/custom/johns_ping.sh new file mode 100644 index 0000000..32af6cb --- /dev/null +++ b/rooter/0optionalapps/pingtest/files/usr/lib/custom/johns_ping.sh @@ -0,0 +1,99 @@ +#!/bin/sh + +. /lib/functions.sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { +logger -t "Custom Ping Test " "$@" +} + +tping() { + hp=$(httping $2 -c 3 -s $1) + pingg=$(echo $hp" " | grep -o "round-trip .\+ ms ") + if [ -z "$pingg" ]; then + tmp=0 + else + tmp=200 + fi +} + +uci set ping.ping.conn="4" +uci commit ping + +CURRMODEM=1 +CPORT=$(uci -q get modem.modem$CURRMODEM.commport) +DELAY=$(uci get ping.ping.delay) + +TYPE=$(uci get ping.ping.type) +if [ $TYPE = "1" ]; then +log "Curl" + RETURN_CODE_1=$(curl -m 10 -s -o /dev/null -w "%{http_code}" http://www.google.com/) + RETURN_CODE_2=$(curl --ipv6 -m 10 -s -o /dev/null -w "%{http_code}" http://www.example.org/) + RETURN_CODE_3=$(curl -m 10 -s -o /dev/null -w "%{http_code}" https://github.com) +else +log "Ping" + tping "http://www.google.com/"; RETURN_CODE_1=$tmp + tping "http://www.example.org/" "-6"; RETURN_CODE_2=$tmp + tping "https://github.com"; RETURN_CODE_3=$tmp +fi + +if [[ "$RETURN_CODE_1" != "200" && "$RETURN_CODE_2" != "200" && "$RETURN_CODE_3" != "200" ]]; then + log "Bad Ping Test" + if [ $TYPE = "1" ]; then + tping "http://www.google.com/"; RETURN_CODE_1=$tmp + tping "http://www.example.org/" "-6"; RETURN_CODE_2=$tmp + tping "https://github.com"; RETURN_CODE_3=$tmp + else + RETURN_CODE_1=$(curl -m 10 -s -o /dev/null -w "%{http_code}" http://www.google.com/) + RETURN_CODE_2=$(curl --ipv6 -m 10 -s -o /dev/null -w "%{http_code}" http://www.example.org/) + RETURN_CODE_3=$(curl -m 10 -s -o /dev/null -w "%{http_code}" https://github.com) + fi + if [[ "$RETURN_CODE_1" != "200" && "$RETURN_CODE_2" != "200" && "$RETURN_CODE_3" != "200" ]]; then + log "Second Bad Ping Test" + uci set ping.ping.conn="3" + uci commit ping + ATCMDD="AT+CFUN=1,1" + $ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD" + sleep $DELAY + tries=0 + while [ $tries -lt 9 ] + do + CONN=$(uci -q get modem.modem$CURRMODEM.connected) + if [ $CONN = "1" ]; then + uci set ping.ping.conn="4" + uci commit ping + if [ $TYPE = "1" ]; then + log "Curl" + RETURN_CODE_1=$(curl -m 10 -s -o /dev/null -w "%{http_code}" http://www.google.com/) + RETURN_CODE_2=$(curl --ipv6 -m 10 -s -o /dev/null -w "%{http_code}" http://www.example.org/) + RETURN_CODE_3=$(curl -m 10 -s -o /dev/null -w "%{http_code}" https://github.com) + else + log "Ping" + tping "http://www.google.com/"; RETURN_CODE_1=$tmp + tping "http://www.example.org/" "-6"; RETURN_CODE_2=$tmp + tping "https://github.com"; RETURN_CODE_3=$tmp + fi + if [[ "$RETURN_CODE_1" != "200" && "$RETURN_CODE_2" != "200" && "$RETURN_CODE_3" != "200" ]]; then + uci set ping.ping.conn="1" + uci commit ping + reboot -f + fi + log "Second Ping Test Good" + uci set ping.ping.conn="2" + uci commit ping + exit 0 + else + sleep 20 + tries=$((tries+1)) + fi + done + reboot -f + fi +else + log "Good Ping" + uci set ping.ping.conn="2" + uci commit ping +fi +exit 0 diff --git a/rooter/0optionalapps/pingtest/files/usr/lib/custom/test_ping.sh b/rooter/0optionalapps/pingtest/files/usr/lib/custom/test_ping.sh new file mode 100644 index 0000000..ab3c5a3 --- /dev/null +++ b/rooter/0optionalapps/pingtest/files/usr/lib/custom/test_ping.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +. /lib/functions.sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { +logger -t "Custom Ping Test " "$@" +} + +sleep 20 +CURRMODEM=1 +uci set ping.ping.conn="1" +uci commit ping +while [ true ] +do + INTER=$(uci get ping.ping.interval) + ENB=$(uci get ping.ping.enable) + if [ $ENB = 0 ]; then + sleep $INTER + else + CONN=$(uci -q get modem.modem$CURRMODEM.connected) + if [ $CONN = "1" ]; then + result=`ps | grep -i "johns_ping.sh" | grep -v "grep" | wc -l` + if [ $result -lt 1 ]; then + /usr/lib/custom/johns_ping.sh & + fi + else + uci set ping.ping.conn="1" + uci commit ping + fi + sleep $INTER + fi +done \ No newline at end of file diff --git a/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/controller/ping.lua b/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/controller/ping.lua new file mode 100644 index 0000000..025d16b --- /dev/null +++ b/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/controller/ping.lua @@ -0,0 +1,16 @@ +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.ping", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + page = entry({"admin", "modem", "ping"}, cbi("ping"), _(translate("Custom Ping Test")), 45) + page.dependent = true + end +end diff --git a/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/model/cbi/ping.lua b/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/model/cbi/ping.lua new file mode 100644 index 0000000..bb52017 --- /dev/null +++ b/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/model/cbi/ping.lua @@ -0,0 +1,42 @@ +local utl = require "luci.util" + +local sys = require "luci.sys" +local zones = require "luci.sys.zoneinfo" +local fs = require "nixio.fs" +local conf = require "luci.config" + +m = Map("ping", translate("Custom Ping Test"), translate("Enable/Disable Custom Ping Test")) + +d = m:section(TypedSection, "ping", " ") +d.anonymous = true + +c1 = d:option(ListValue, "enable", translate("Ping Test Status : "), translate("Ping every 20 seconds and, if it fails, restart modem or reboot router")); +c1:value("0", translate("Disabled")) +c1:value("1", translate("Enabled")) +c1.default=0 + +interval = d:option(Value, "interval", translate("Test Interval :"), translate("Number of seconds between testing the connection. Range is 20 to 120 secs.")); +interval.rmempty = true; +interval.optional=false; +interval.datatype = 'range(20,120)'; +interval.default="20"; + +type = d:option(ListValue, "type", translate("Test Type :"), translate("Type of test - Page Retrieval or Ping")); +type:value("0", translate("Ping")) +type:value("1", translate("Page Retrieval")) +type.default=1 + +d1 = d:option(ListValue, "delay", translate("Reconnection Delay"),translate("Delay in seconds after restarting modem before checking for connection")); +d1:value("40", "40 seconds") +d1:value("45", "45 seconds") +d1:value("50", "50 seconds") +d1:value("55", "55 seconds") +d1:value("60", "60 seconds") +d1:value("70", "70 seconds") +d1:value("80", "80 seconds") +d1:value("90", "90 seconds") +d1:value("100", "100 seconds") +d1:value("120", "120 seconds") +d1.default=40 + +return m \ No newline at end of file diff --git a/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/view/admin_status/index/extping.htm b/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/view/admin_status/index/extping.htm new file mode 100644 index 0000000..ed0c240 --- /dev/null +++ b/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/view/admin_status/index/extping.htm @@ -0,0 +1 @@ +<%+pingtest/extping%> \ No newline at end of file diff --git a/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/view/pingtest/extping.htm b/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/view/pingtest/extping.htm new file mode 100644 index 0000000..daba06c --- /dev/null +++ b/rooter/0optionalapps/pingtest/files/usr/lib/lua/luci/view/pingtest/extping.htm @@ -0,0 +1,26 @@ + + +
                          + <%:Custom Ping Test Status%> + + +
                          <%:Ping Status%><%:Loading%> Collecting data...
                          +
                          + diff --git a/rooter/0optionalapps/qfirehose/Makefile b/rooter/0optionalapps/qfirehose/Makefile new file mode 100644 index 0000000..6ceb348 --- /dev/null +++ b/rooter/0optionalapps/qfirehose/Makefile @@ -0,0 +1,40 @@ +# +# Copyright (C) 2011-2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=qfirehose +PKG_RELEASE:=1 + +PKG_FLAGS:=nonshared + +include $(INCLUDE_DIR)/package.mk + +define Package/qfirehose + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + TITLE:=Quectel FireHose + MAINTAINER:=Dairyman +endef + +define Package/qfirehose/description + Quectel FireHose +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" \ + CFLAGS="$(TARGET_CFLAGS) -Wall" +endef + +define Package/qfirehose/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/qfirehose $(1)/usr/bin/QFirehose +endef + +$(eval $(call BuildPackage,qfirehose)) diff --git a/rooter/0optionalapps/qfirehose/src/Makefile b/rooter/0optionalapps/qfirehose/src/Makefile new file mode 100644 index 0000000..44864b7 --- /dev/null +++ b/rooter/0optionalapps/qfirehose/src/Makefile @@ -0,0 +1,7 @@ +all: qfirehose + +qfirehose: + $(CC) $(CFLAGS) -Wall firehose_protocol.c qfirehose.c sahara_protocol.c usb_linux.c stream_download_protocol.c md5.c usb2tcp.c -o $@ $^ + +clean: + rm -rf firehose obj libs diff --git a/rooter/0optionalapps/qfirehose/src/firehose_protocol.c b/rooter/0optionalapps/qfirehose/src/firehose_protocol.c new file mode 100644 index 0000000..25c6ea1 --- /dev/null +++ b/rooter/0optionalapps/qfirehose/src/firehose_protocol.c @@ -0,0 +1,1087 @@ +/****************************************************************************** + @file firehose_protocol.c + @brief firehose protocol. + + DESCRIPTION + QFirehoe Tool for USB and PCIE of Quectel wireless cellular modules. + + INITIALIZATION AND SEQUENCING REQUIREMENTS + None. + + --------------------------------------------------------------------------- + Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved. + Quectel Wireless Solution Proprietary and Confidential. + --------------------------------------------------------------------------- +******************************************************************************/ +#include "usb_linux.h" +#include +#include +#include + +#define error_return() do {dbg_time("%s %s %d fail\n", __FILE__, __func__, __LINE__); return __LINE__; } while(0) +int recv_sc600y_configure_num = 1; +extern int g_is_sc600y_chip; + +extern unsigned q_erase_all_before_download; +extern int update_transfer_bytes(long long bytes_cur); +extern int show_progress(); + +struct fh_configure_cmd { + const char *type; + const char *MemoryName; + uint32_t Verbose; + uint32_t AlwaysValidate; + uint32_t MaxDigestTableSizeInBytes; + uint32_t MaxPayloadSizeToTargetInBytes; + uint32_t MaxPayloadSizeFromTargetInBytes ; //2048 + uint32_t MaxPayloadSizeToTargetInByteSupported; //16k + uint32_t ZlpAwareHost; + uint32_t SkipStorageInit; +}; + +struct fh_erase_cmd { + const char *type; + uint32_t PAGES_PER_BLOCK; + uint32_t SECTOR_SIZE_IN_BYTES; + char label[32]; + uint32_t last_sector; + uint32_t num_partition_sectors; + uint32_t physical_partition_number; + uint32_t start_sector; +}; + +struct fh_program_cmd { + const char *type; + char *filename; + uint32_t filesz; + uint32_t PAGES_PER_BLOCK; + uint32_t SECTOR_SIZE_IN_BYTES; + char label[32]; + uint32_t last_sector; + uint32_t num_partition_sectors; + uint32_t physical_partition_number; + uint32_t start_sector; +}; + +struct fh_response_cmd { + const char *type; + const char *value; + uint32_t rawmode; + uint32_t MaxPayloadSizeToTargetInBytes; +}; + +struct fh_log_cmd { + const char *type; +}; + +struct fh_patch_cmd { + const char *type; + char *filename; + uint32_t filesz; + uint32_t SECTOR_SIZE_IN_BYTES; + uint32_t num_partition_sectors; +}; + +struct fh_cmd_header { + const char *type; +}; + +struct fh_vendor_defines { + const char *type; // "vendor" + char buffer[256]; +}; + +struct fh_cmd { + union { + struct fh_cmd_header cmd; + struct fh_configure_cmd cfg; + struct fh_erase_cmd erase; + struct fh_program_cmd program; + struct fh_response_cmd response; + struct fh_log_cmd log; + struct fh_patch_cmd patch; + struct fh_vendor_defines vdef; + }; + int part_upgrade; + char xml_original_data[300]; +}; + +struct fh_data { + const char *firehose_dir; + const void *usb_handle; + unsigned MaxPayloadSizeToTargetInBytes; + unsigned fh_cmd_count; + unsigned ZlpAwareHost; + struct fh_cmd fh_cmd_table[128]; //AG525 have more than 64 partition + + unsigned xml_tx_size; + unsigned xml_rx_size; + char xml_tx_buf[1024]; + char xml_rx_buf[1024]; +}; + +static const char * fh_xml_get_value(const char *xml_line, const char *key) { + static char value[64]; + + char *pchar = strstr(xml_line, key); + char *pend; + + if (!pchar) { + dbg_time("%s: no key %s in %s\n", __func__, key, xml_line); + return NULL; + } + + pchar += strlen(key); + if (pchar[0] != '=' && pchar[1] != '"') { + dbg_time("%s: no start %s in %s\n", __func__, "=\"", xml_line); + return NULL; + } + + pchar += strlen("=\""); + pend = strstr(pchar, "\""); + if (!pend) { + dbg_time("%s: no end %s in %s\n", __func__, "\"", xml_line); + return NULL; + } + + strncpy(value, pchar, pend - pchar); + value[pend - pchar] = '\0'; + + //dbg_time("%s=%s\n", key, value); + + return value; +} + +static int fh_parse_xml_line(const char *xml_line, struct fh_cmd *fh_cmd) { + const char *pchar = NULL; + char *pret; + + memset(fh_cmd, 0, sizeof( struct fh_cmd)); + if (strstr(xml_line, "vendor=\"quectel\"")) { + fh_cmd->vdef.type = "vendor"; + snprintf(fh_cmd->vdef.buffer, sizeof(fh_cmd->vdef.buffer), "%.255s", xml_line); + return 0; + } + else if (!strncmp(xml_line, "erase.type = "erase"; + if ((pchar = fh_xml_get_value(xml_line, "PAGES_PER_BLOCK"))) + fh_cmd->erase.PAGES_PER_BLOCK = atoi(pchar); + if ((pchar = fh_xml_get_value(xml_line, "SECTOR_SIZE_IN_BYTES"))) + fh_cmd->erase.SECTOR_SIZE_IN_BYTES = atoi(pchar); + if (strstr(xml_line, "last_sector")) { + if ((pchar = fh_xml_get_value(xml_line, "last_sector"))) + fh_cmd->erase.last_sector = atoi(pchar); + if (strstr(xml_line, "label")) { + if ((pchar = fh_xml_get_value(xml_line, "label"))) + strcpy(fh_cmd->erase.label, pchar); + } + } + if ((pchar = fh_xml_get_value(xml_line, "num_partition_sectors"))) + fh_cmd->erase.num_partition_sectors = strtoul(pchar, &pret, 10); + if ((pchar = fh_xml_get_value(xml_line, "physical_partition_number"))) + fh_cmd->erase.physical_partition_number = atoi(pchar); + if ((pchar = fh_xml_get_value(xml_line, "start_sector"))) + fh_cmd->erase.start_sector = atoi(pchar); + return 0; + } + else if (!strncmp(xml_line, "program.type = "program"; + if ((pchar = fh_xml_get_value(xml_line, "filename"))) + { + fh_cmd->program.filename = strdup(pchar); + if(fh_cmd->program.filename[0] == '\0') + {//some fw version have blank program line, ignore it. + return -1; + } + } + if (!g_is_sc600y_chip) + { + if ((pchar = fh_xml_get_value(xml_line, "PAGES_PER_BLOCK"))) + fh_cmd->program.PAGES_PER_BLOCK = atoi(pchar); + if ((pchar = fh_xml_get_value(xml_line, "SECTOR_SIZE_IN_BYTES"))) + fh_cmd->program.SECTOR_SIZE_IN_BYTES = atoi(pchar); + if (strstr(xml_line, "last_sector")) { + if ((pchar = fh_xml_get_value(xml_line, "last_sector"))) + fh_cmd->program.last_sector = atoi(pchar); + if (strstr(xml_line, "label")) { + if ((pchar = fh_xml_get_value(xml_line, "label"))) + strcpy(fh_cmd->program.label, pchar); + } + } + if ((pchar = fh_xml_get_value(xml_line, "num_partition_sectors"))) + fh_cmd->program.num_partition_sectors = atoi(pchar); + if ((pchar = fh_xml_get_value(xml_line, "physical_partition_number"))) + fh_cmd->program.physical_partition_number = atoi(pchar); + if ((pchar = fh_xml_get_value(xml_line, "start_sector"))) + fh_cmd->program.start_sector = atoi(pchar); + } + else + { + if ((pchar = fh_xml_get_value(xml_line, "start_sector"))) + fh_cmd->program.start_sector = atoi(pchar); + if ((pchar = fh_xml_get_value(xml_line, "num_partition_sectors"))) + fh_cmd->program.num_partition_sectors = atoi(pchar); + if ((pchar = fh_xml_get_value(xml_line, "SECTOR_SIZE_IN_BYTES"))) + fh_cmd->program.SECTOR_SIZE_IN_BYTES = atoi(pchar); + strcpy(fh_cmd->xml_original_data, xml_line); + } + + return 0; + } + else if (!strncmp(xml_line, "patch.type = "patch"; + if ((pchar = fh_xml_get_value(xml_line, "filename"))) + { + fh_cmd->patch.filename = strdup(pchar); + if(fh_cmd->patch.filename[0] == '\0' || strncasecmp(fh_cmd->patch.filename, "DISK",4)) + {//some fw version have blank program line, ignore it. + return -1; + } + } + strcpy(fh_cmd->xml_original_data, xml_line); + + return 0; + } + else if (!strncmp(xml_line, "response.type = "response"; + pchar = fh_xml_get_value(xml_line, "value"); + if (pchar) { + if (!strcmp(pchar, "ACK")) + fh_cmd->response.value = "ACK"; + else if(!strcmp(pchar, "NAK")) + fh_cmd->response.value = "NAK"; + else + fh_cmd->response.value = "OTHER"; + } + if (strstr(xml_line, "rawmode")) { + pchar = fh_xml_get_value(xml_line, "rawmode"); + if (pchar) { + fh_cmd->response.rawmode = !strcmp(pchar, "true"); + } + } + else if (strstr(xml_line, "MaxPayloadSizeToTargetInBytes")) { + pchar = fh_xml_get_value(xml_line, "MaxPayloadSizeToTargetInBytes"); + if (pchar) { + fh_cmd->response.MaxPayloadSizeToTargetInBytes = atoi(pchar); + } + } + return 0; + } + else if (!strncmp(xml_line, "program.type = "log"; + return 0; + } + + error_return(); +} + +static int fh_parse_xml_file(struct fh_data *fh_data, const char *xml_file) { + FILE *fp = fopen(xml_file, "rb"); + + if (fp == NULL) { + dbg_time("%s fail to fopen(%s), errno: %d (%s)\n", __func__, xml_file, errno, strerror(errno)); + error_return(); + } + + while (fgets(fh_data->xml_tx_buf, fh_data->xml_tx_size, fp)) { + char *xml_line = strstr(fh_data->xml_tx_buf, "<"); + + if (xml_line && strstr(xml_line, "")) { + if (strstr(xml_line, "/>") < strstr(xml_line, "") && strstr(xml_line, " SAHARA_RESET"); + if (0 == sahara_tx_data (usb_handle, tx_buffer, sizeof(sahara_packet_reset))) { + dbg(LOG_ERROR, "Sending RESET packet failed"); + return 0; + } + + return 1; +#endif +} + +static int send_done_packet (void *usb_handle, void *tx_buffer) { + sahara_packet_done *sahara_done = (sahara_packet_done *)tx_buffer; + + sahara_done->header.command = le_uint32(SAHARA_DONE_ID); + sahara_done->header.length = le_uint32(sizeof(sahara_packet_done)); + // Send the image data + dbg(LOG_EVENT, "SENDING --> SAHARA_DONE"); + if (0 == sahara_tx_data (usb_handle, tx_buffer, sizeof(sahara_packet_done))) { + dbg(LOG_ERROR, "Sending DONE packet failed"); + return 0; + } + return 1; +} + +static int start_image_transfer(void *usb_handle, void *tx_buffer, const sahara_packet_read_data *sahara_read_data, FILE *file_handle) +{ + int retval = 0; + uint32_t bytes_read = 0, bytes_to_read_next; + uint32_t DataOffset = le_uint32(sahara_read_data->data_offset); + uint32_t DataLength = le_uint32(sahara_read_data->data_length); + + dbg(LOG_INFO, "0x%08x 0x%08x 0x%08x", le_uint32(sahara_read_data->image_id), DataOffset, DataLength); + + if (fseek(file_handle, (long)DataOffset, SEEK_SET)) { + dbg(LOG_INFO, "%d errno: %d (%s)", __LINE__, errno, strerror(errno)); + return 0; + } + + while (bytes_read < DataLength) { + bytes_to_read_next = MIN((uint32_t)DataLength - bytes_read, SAHARA_RAW_BUFFER_SIZE); + retval = fread(tx_buffer, 1, bytes_to_read_next, file_handle); + + if (retval < 0) { + dbg(LOG_ERROR, "file read failed: %s", strerror(errno)); + return 0; + } + + if ((uint32_t) retval != bytes_to_read_next) { + dbg(LOG_ERROR, "Read %d bytes, but was asked for 0x%08x bytes", retval, DataLength); + return 0; + } + + /*send the image data*/ + if (0 == sahara_tx_data (usb_handle, tx_buffer, bytes_to_read_next)) { + dbg(LOG_ERROR, "Tx Sahara Image Failed"); + return 0; + } + + bytes_read += bytes_to_read_next; + } + + return 1; +} + +static int sahara_start(void *usb_handle, void *tx_buffer, void *rx_buffer, FILE *file_handle) { + uint32_t image_id = 0; + sahara_packet_header* sahara_cmd = (sahara_packet_header *)rx_buffer; + sahara_packet_hello *sahara_hello = (sahara_packet_hello *)rx_buffer; + sahara_packet_read_data *sahara_read_data = (sahara_packet_read_data *)rx_buffer; + sahara_packet_done_resp *sahara_done_resp = (sahara_packet_done_resp *)rx_buffer; + sahara_packet_end_image_tx *sahara_end_image_tx = (sahara_packet_end_image_tx *)rx_buffer; + + sahara_packet_hello_resp *sahara_hello_resp = (sahara_packet_hello_resp *)tx_buffer; + + dbg(LOG_EVENT, "STATE <-- SAHARA_WAIT_HELLO"); + if (0 == sahara_rx_data(usb_handle, rx_buffer, 0)) { +#if 0 + unsigned char edl_cmd[] = {0x4b, 0x65, 0x01, 0x00, 0x54, 0x0f, 0x7e}; + sahara_tx_data(usb_handle, edl_cmd, sizeof(edl_cmd)); +#else + sahara_tx_data(usb_handle, tx_buffer, 1); +#endif + if (0 == sahara_rx_data(usb_handle, rx_buffer, 0)) + return 0; + } + + //Check if the received command is a hello command + if (le_uint32(sahara_cmd->command) != SAHARA_HELLO_ID) { + dbg(LOG_ERROR, "Received a different command: %x while waiting for hello packet", sahara_hello->header.command); + send_reset_command(usb_handle, rx_buffer); + return 0; + } + + // Recieved hello, send the hello response + //Create a Hello request + sahara_hello_resp->header.command = le_uint32(SAHARA_HELLO_RESP_ID); + sahara_hello_resp->header.length = le_uint32(sizeof(sahara_packet_hello_resp)); + sahara_hello_resp->version = sahara_hello->version; //SAHARA_VERSION; + sahara_hello_resp->version_supported = sahara_hello->version_supported; //SAHARA_VERSION_SUPPORTED; + sahara_hello_resp->status = le_uint32(SAHARA_STATUS_SUCCESS); + sahara_hello_resp->mode = sahara_hello->mode; + sahara_hello_resp->reserved0 = le_uint32(1); + sahara_hello_resp->reserved1 = le_uint32(2); + sahara_hello_resp->reserved2 = le_uint32(3); + sahara_hello_resp->reserved3 = le_uint32(4); + sahara_hello_resp->reserved4 = le_uint32(5); + sahara_hello_resp->reserved5 = le_uint32(6); + + switch (le_uint32(sahara_hello->mode)) { + case SAHARA_MODE_IMAGE_TX_PENDING: + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_IMAGE_TX_PENDING"); + break; + case SAHARA_MODE_IMAGE_TX_COMPLETE: + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_IMAGE_TX_COMPLETE"); + break; + case SAHARA_MODE_MEMORY_DEBUG: + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_MEMORY_DEBUG"); + break; + case SAHARA_MODE_COMMAND: + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_COMMAND"); + break; + default: + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_0x%x", le_uint32(sahara_hello->mode)); + break; + } + + if (le_uint32(sahara_hello->mode) != SAHARA_MODE_IMAGE_TX_PENDING) { + dbg(LOG_ERROR, "ERROR NOT SAHARA_MODE_IMAGE_TX_PENDING"); + sahara_hello_resp->mode = SAHARA_MODE_IMAGE_TX_PENDING; + } + + /*Send the Hello Resonse Request*/ + dbg(LOG_EVENT, "SENDING --> SAHARA_HELLO_RESPONSE"); + if (0 == sahara_tx_data (usb_handle, tx_buffer, sizeof(sahara_packet_hello_resp))) { + dbg(LOG_ERROR, "Tx Sahara Data Failed "); + return 0; + } + + while (1) { + dbg(LOG_INFO, "STATE <-- SAHARA_WAIT_COMMAND"); + if (0 == sahara_rx_data(usb_handle, rx_buffer, 0)) + return 0; + + if (le_uint32(sahara_cmd->command) == SAHARA_READ_DATA_ID) { + start_image_transfer(usb_handle, tx_buffer, sahara_read_data, file_handle); + } + else if (le_uint32(sahara_cmd->command) == SAHARA_END_IMAGE_TX_ID) { + dbg(LOG_EVENT, "image_id = %d, status = %d", le_uint32(sahara_end_image_tx->image_id), le_uint32(sahara_end_image_tx->status)); + if (le_uint32(sahara_end_image_tx->status) == SAHARA_STATUS_SUCCESS) { + image_id = le_uint32(sahara_end_image_tx->image_id); + send_done_packet (usb_handle, tx_buffer); + break; + } else { + return 0; + } + } + else if (le_uint32(sahara_cmd->command) == SAHARA_HELLO_ID) { + continue; + } + else { + dbg(LOG_ERROR, "Received an unknown command: %d ", le_uint32(sahara_cmd->command)); + send_reset_command (usb_handle, tx_buffer); + return 0; + } + } + + dbg(LOG_EVENT, "STATE <-- SAHARA_WAIT_DONE_RESP"); + if (0 == sahara_rx_data(usb_handle, rx_buffer, 0)) + return 0; + + dbg(LOG_INFO, "image_tx_status = %d", le_uint32(sahara_done_resp->image_tx_status)); + + if (SAHARA_MODE_IMAGE_TX_PENDING == le_uint32(sahara_done_resp->image_tx_status)) { + if (image_id == 13) //prog_nand_firehose_9x07.mbn + return 1; + if (image_id == 7) //NPRG9x55.mbn + return 1; + if (image_id == 21) //sbl1.mbn, October 22 2020 2:12 PM, AG35CEVAR05A07T4G + return 1; + } + else if (SAHARA_MODE_IMAGE_TX_COMPLETE == le_uint32(sahara_done_resp->image_tx_status)) { + dbg(LOG_EVENT,"Successfully uploaded all images"); + return 1; + } + else { + dbg(LOG_ERROR, "Received unrecognized status %d at SAHARA_WAIT_DONE_RESP state", + le_uint32(sahara_done_resp->image_tx_status)); + return 0; + } + + return 0; +} + +int sahara_main(const char *firehose_dir, void *usb_handle, int edl_mode_05c69008) { + int retval = 0; + char* prog_nand_firehose_filename = NULL; + char full_path[512]; + FILE *file_handle; + void *tx_buffer; + void *rx_buffer; + + if (edl_mode_05c69008) { + if(qfile_find_xmlfile(firehose_dir, "prog", &prog_nand_firehose_filename) != 0 + && qfile_find_xmlfile(firehose_dir, "prog_firehose", &prog_nand_firehose_filename) != 0) { + dbg(LOG_ERROR, "retrieve prog nand firehose failed."); + return ENOENT; + } + dbg(LOG_INFO, "prog_nand_firehose_filename = %s", prog_nand_firehose_filename); + + if (!strncmp(prog_nand_firehose_filename, "prog_emmc_firehose_8953_ddr.mbn", strlen(prog_nand_firehose_filename))) + g_is_sc600y_chip = 1; + + snprintf(full_path, sizeof(full_path), "%.255s/%.240s", firehose_dir, prog_nand_firehose_filename); + } + else { + snprintf(full_path, sizeof(full_path), "%.255s/..", firehose_dir); + if(qfile_find_xmlfile(full_path, "NPRG9x", &prog_nand_firehose_filename) != 0 + && qfile_find_xmlfile(full_path, "NPRG9x", &prog_nand_firehose_filename) != 0) { + dbg(LOG_ERROR, "retrieve NPRG MBN failed."); + return ENOENT; + } + dbg(LOG_INFO, "prog_nand_firehose_filename = %s", prog_nand_firehose_filename); + + snprintf(full_path, sizeof(full_path), "%.255s/../%.240s", firehose_dir, prog_nand_firehose_filename); + } + + free(prog_nand_firehose_filename); + file_handle = fopen(full_path, "rb"); + if (file_handle == NULL) { + dbg(LOG_INFO, "%s %d %s errno: %d (%s)", __func__, __LINE__, full_path, errno, strerror(errno)); + return ENOENT; + } + + rx_buffer = malloc (SAHARA_RAW_BUFFER_SIZE); + tx_buffer = malloc (SAHARA_RAW_BUFFER_SIZE); + + if (NULL == rx_buffer || NULL == tx_buffer) { + dbg(LOG_ERROR, "Failed to allocate sahara buffers"); + return ENOMEM; + } + + retval = sahara_start(usb_handle, tx_buffer, rx_buffer, file_handle); + if (0 == retval) { + dbg(LOG_ERROR, "Sahara protocol error"); + } + else { + dbg(LOG_STATUS, "Sahara protocol completed"); + } + + free(rx_buffer); + free(tx_buffer); + fclose(file_handle); + + if (retval) + return 0; + + return __LINE__; +} diff --git a/rooter/0optionalapps/qfirehose/src/sahara_protocol.h b/rooter/0optionalapps/qfirehose/src/sahara_protocol.h new file mode 100644 index 0000000..bb88a2c --- /dev/null +++ b/rooter/0optionalapps/qfirehose/src/sahara_protocol.h @@ -0,0 +1,385 @@ +/*=========================================================================== + * FILE: + * sahara_packet.h + * + * DESCRIPTION: + * Sahara protocol states and structure declaration. + * + * Copyright (C) 2012 Qualcomm Technologies, Inc. All rights reserved. + * Qualcomm Technologies Proprietary/GTDR + * + * All data and information contained in or disclosed by this document is + * confidential and proprietary information of Qualcomm Technologies, Inc. and all + * rights therein are expressly reserved. By accepting this material the + * recipient agrees that this material and the information contained therein + * is held in confidence and in trust and will not be used, copied, reproduced + * in whole or in part, nor its contents revealed in any manner to others + * without the express written permission of Qualcomm Technologies, Inc. + * =========================================================================== + * + * sahara_packet.h : Sahara protocol states and structure declaration. + * ========================================================================================== + * $Header: //components/rel/boot.bf/3.1.4/boot_images/core/storage/tools/QSaharaServer/src/sahara_protocol.h#1 $ + * $DateTime: 2017/02/21 04:58:32 $ + * $Author: pwbldsvc $ + * + * Edit History: + * YYYY-MM-DD who why + * ----------------------------------------------------------------------------- + * 2010-09-28 ng Added command mode support + * 2010-10-18 ab Added memory debug mode support + * + * Copyright 2012 by Qualcomm Technologies, Inc. All Rights Reserved. + * + *========================================================================================== + */ + +#ifndef SAHARA_PROTOCOL_H +#define SAHARA_PROTOCOL_H + +/*=========================================================================== + * + * INCLUDE FILES + * + * ===========================================================================*/ + +/*=========================================================================== + * + * PUBLIC DATA DECLARATIONS + * + * ===========================================================================*/ +// Sahara Protocol Version +#define SAHARA_VERSION 2 +#define SAHARA_VERSION_SUPPORTED 4 + +/*Maximum 1 megabyte tx buffer size*/ + +#define SAHARA_RAW_BUFFER_SIZE (4*1024) + +// Sahara command IDs +typedef enum +{ + SAHARA_NO_CMD_ID = 0x00, + SAHARA_HELLO_ID = 0x01, // sent from target to host + SAHARA_HELLO_RESP_ID = 0x02, // sent from host to target + SAHARA_READ_DATA_ID = 0x03, // sent from target to host + SAHARA_END_IMAGE_TX_ID = 0x04, // sent from target to host + SAHARA_DONE_ID = 0x05, // sent from host to target + SAHARA_DONE_RESP_ID = 0x06, // sent from target to host + SAHARA_RESET_ID = 0x07, // sent from host to target + SAHARA_RESET_RESP_ID = 0x08, // sent from target to host + SAHARA_MEMORY_DEBUG_ID = 0x09, // sent from target to host + SAHARA_MEMORY_READ_ID = 0x0A, // sent from host to target + SAHARA_CMD_READY_ID = 0x0B, // sent from target to host + SAHARA_CMD_SWITCH_MODE_ID = 0x0C, // sent from host to target + SAHARA_CMD_EXEC_ID = 0x0D, // sent from host to target + SAHARA_CMD_EXEC_RESP_ID = 0x0E, // sent from target to host + SAHARA_CMD_EXEC_DATA_ID = 0x0F, // sent from host to target + SAHARA_64_BITS_MEMORY_DEBUG_ID = 0x10, // sent from target to host + SAHARA_64_BITS_MEMORY_READ_ID = 0x11, // sent from host to target + SAHARA_64_BITS_READ_DATA_ID = 0x12, + // place all new commands above this + SAHARA_LAST_CMD_ID, + SAHARA_MAX_CMD_ID = 0x7FFFFFFF // To ensure 32-bits wide +} boot_sahara_cmd_id; + +typedef enum { + SAHARA_IMAGE_TYPE_BINARY = 0, /* Binary format */ + SAHARA_IMAGE_TYPE_ELF, /* ELF format */ + SAHARA_IMAGE_UNKNOWN = 0x7FFFFFFF /* To ensure 32-bits wide */ +} boot_sahara_image; + +// Status codes for Sahara +typedef enum +{ + // Success + SAHARA_STATUS_SUCCESS = 0x00, + + // Invalid command received in current state + SAHARA_NAK_INVALID_CMD = 0x01, + + // Protocol mismatch between host and target + SAHARA_NAK_PROTOCOL_MISMATCH = 0x02, + + // Invalid target protocol version + SAHARA_NAK_INVALID_TARGET_PROTOCOL = 0x03, + + // Invalid host protocol version + SAHARA_NAK_INVALID_HOST_PROTOCOL = 0x04, + + // Invalid packet size received + SAHARA_NAK_INVALID_PACKET_SIZE = 0x05, + + // Unexpected image ID received + SAHARA_NAK_UNEXPECTED_IMAGE_ID = 0x06, + + // Invalid image header size received + SAHARA_NAK_INVALID_HEADER_SIZE = 0x07, + + // Invalid image data size received + SAHARA_NAK_INVALID_DATA_SIZE = 0x08, + + // Invalid image type received + SAHARA_NAK_INVALID_IMAGE_TYPE = 0x09, + + // Invalid tranmission length + SAHARA_NAK_INVALID_TX_LENGTH = 0x0A, + + // Invalid reception length + SAHARA_NAK_INVALID_RX_LENGTH = 0x0B, + + // General transmission or reception error + SAHARA_NAK_GENERAL_TX_RX_ERROR = 0x0C, + + // Error while transmitting READ_DATA packet + SAHARA_NAK_READ_DATA_ERROR = 0x0D, + + // Cannot receive specified number of program headers + SAHARA_NAK_UNSUPPORTED_NUM_PHDRS = 0x0E, + + // Invalid data length received for program headers + SAHARA_NAK_INVALID_PDHR_SIZE = 0x0F, + + // Multiple shared segments found in ELF image + SAHARA_NAK_MULTIPLE_SHARED_SEG = 0x10, + + // Uninitialized program header location + SAHARA_NAK_UNINIT_PHDR_LOC = 0x11, + + // Invalid destination address + SAHARA_NAK_INVALID_DEST_ADDR = 0x12, + + // Invalid data size receieved in image header + SAHARA_NAK_INVALID_IMG_HDR_DATA_SIZE = 0x13, + + // Invalid ELF header received + SAHARA_NAK_INVALID_ELF_HDR = 0x14, + + // Unknown host error received in HELLO_RESP + SAHARA_NAK_UNKNOWN_HOST_ERROR = 0x15, + + // Timeout while receiving data + SAHARA_NAK_TIMEOUT_RX = 0x16, + + // Timeout while transmitting data + SAHARA_NAK_TIMEOUT_TX = 0x17, + + // Invalid mode received from host + SAHARA_NAK_INVALID_HOST_MODE = 0x18, + + // Invalid memory read access + SAHARA_NAK_INVALID_MEMORY_READ = 0x19, + + // Host cannot handle read data size requested + SAHARA_NAK_INVALID_DATA_SIZE_REQUEST = 0x1A, + + // Memory debug not supported + SAHARA_NAK_MEMORY_DEBUG_NOT_SUPPORTED = 0x1B, + + // Invalid mode switch + SAHARA_NAK_INVALID_MODE_SWITCH = 0x1C, + + // Failed to execute command + SAHARA_NAK_CMD_EXEC_FAILURE = 0x1D, + + // Invalid parameter passed to command execution + SAHARA_NAK_EXEC_CMD_INVALID_PARAM = 0x1E, + + // Unsupported client command received + SAHARA_NAK_EXEC_CMD_UNSUPPORTED = 0x1F, + + // Invalid client command received for data response + SAHARA_NAK_EXEC_DATA_INVALID_CLIENT_CMD = 0x20, + + // Failed to authenticate hash table + SAHARA_NAK_HASH_TABLE_AUTH_FAILURE = 0x21, + + // Failed to verify hash for a given segment of ELF image + SAHARA_NAK_HASH_VERIFICATION_FAILURE = 0x22, + + // Failed to find hash table in ELF image + SAHARA_NAK_HASH_TABLE_NOT_FOUND = 0x23, + + // Place all new error codes above this + SAHARA_NAK_LAST_CODE, + + SAHARA_NAK_MAX_CODE = 0x7FFFFFFF // To ensure 32-bits wide +} boot_sahara_status; + +// Status of all image transfers +typedef enum +{ + SAHARA_MODE_IMAGE_TX_PENDING = 0x0, + SAHARA_MODE_IMAGE_TX_COMPLETE = 0x1, + SAHARA_MODE_MEMORY_DEBUG = 0x2, + SAHARA_MODE_COMMAND = 0x3, + + // place all new commands above this + SAHARA_MODE_LAST, + SAHARA_MODE_MAX = 0x7FFFFFFF +} boot_sahara_mode; + +// Executable commands when target is in command mode +typedef enum +{ + SAHARA_EXEC_CMD_NOP = 0x00, + SAHARA_EXEC_CMD_SERIAL_NUM_READ = 0x01, + SAHARA_EXEC_CMD_MSM_HW_ID_READ = 0x02, + SAHARA_EXEC_CMD_OEM_PK_HASH_READ = 0x03, + SAHARA_EXEC_CMD_SWITCH_DMSS = 0x04, + SAHARA_EXEC_CMD_SWITCH_STREAMING = 0x05, + SAHARA_EXEC_CMD_READ_DEBUG_DATA = 0x06, + + // place all new commands above this + SAHARA_EXEC_CMD_LAST, + SAHARA_EXEC_CMD_MAX = 0x7FFFFFFF +} boot_sahara_exec_cmd_id; + +/* Sahara Protocol states */ +typedef enum { + SAHARA_WAIT_HELLO, + SAHARA_WAIT_COMMAND, + SAHARA_WAIT_RESET_RESP, + SAHARA_WAIT_DONE_RESP, + SAHARA_WAIT_MEMORY_READ, + SAHARA_WAIT_CMD_EXEC_RESP, + SAHARA_WAIT_MEMORY_TABLE, + SAHARA_WAIT_MEMORY_REGION, +} boot_sahara_state; + +/* ============================================================================= */ +/* Sahara protocol packet defintions */ +/* ============================================================================= */ + +typedef struct +{ + uint32_t command; // command ID + uint32_t length; // packet length incl command and length +} sahara_packet_header; + +// HELLO command packet type - sent from target to host +// indicates start of protocol on target side +typedef struct +{ + sahara_packet_header header; + uint32_t version; // target protocol version number + uint32_t version_supported; // minimum protocol version number supported + // on target + uint32_t cmd_packet_length; // maximum packet size supported for command + // packets + uint32_t mode; // expected mode of target operation + uint32_t reserved0; // reserved field + uint32_t reserved1; // reserved field + uint32_t reserved2; // reserved field + uint32_t reserved3; // reserved field + uint32_t reserved4; // reserved field + uint32_t reserved5; // reserved field +} sahara_packet_hello; + +// HELLO_RESP command packet type - sent from host to target +// response to hello, protocol version running on host and status sent +typedef struct +{ + sahara_packet_header header; + uint32_t version; // host protocol version number + uint32_t version_supported; // minimum protocol version number supported + // on host + uint32_t status; // OK or error condition + uint32_t mode; // mode of operation for target to execute + uint32_t reserved0; // reserved field + uint32_t reserved1; // reserved field + uint32_t reserved2; // reserved field + uint32_t reserved3; // reserved field + uint32_t reserved4; // reserved field + uint32_t reserved5; // reserved field +} sahara_packet_hello_resp; + +// READ_DATA command packet type - sent from target to host +// sends data segment offset and length to be read from current host +// image file +typedef struct +{ + sahara_packet_header header; + uint32_t image_id; // ID of image to be transferred + uint32_t data_offset; // offset into image file to read data from + uint32_t data_length; // length of data segment to be retreived + // from image file +} sahara_packet_read_data; + +// READ_DATA_64 command packet type - sent from target to host +// sends data segment offset and length to be read from current host +// image file +/* +#ifdef WINDOWSPC +#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) ) +PACK( +typedef struct // note for gcc use __attribute__((__packed__)) +{ + sahara_packet_header header; + uint32_t image_id; // ID of image to be transferred + uint64_t data_offset; // offset into image file to read data from + uint32_t data_length; // length of data segment to be retreived + // from image file +} sahara_packet_read_data_64bit; +); +#else +typedef __attribute__((__packed__)) struct +{ + sahara_packet_header header; + uint32_t image_id; // ID of image to be transferred + uint64_t data_offset; // offset into image file to read data from + uint32_t data_length; // length of data segment to be retreived + // from image file +} sahara_packet_read_data_64bit; +#endif +*/ +typedef struct +{ + sahara_packet_header header; + uint64_t image_id; // ID of image to be transferred + uint64_t data_offset; // offset into image file to read data from + uint64_t data_length; // length of data segment to be retreived + // from image file +} sahara_packet_read_data_64bit; + +// END_IMAGE_TX command packet type - sent from target to host +// indicates end of a single image transfer and status of transfer +typedef struct +{ + sahara_packet_header header; + uint32_t image_id; // ID of image to be transferred + uint32_t status; // OK or error condition +} sahara_packet_end_image_tx; + +// DONE packet type - sent from host to target +// indicates end of single image transfer +typedef struct +{ + sahara_packet_header header; +} sahara_packet_done; + +// DONE_RESP packet type - sent from target to host +// indicates end of all image transfers +typedef struct +{ + sahara_packet_header header; + uint32_t image_tx_status; // indicates if all images have been + // transferred; + // 0 = IMAGE_TX_PENDING + // 1 = IMAGE_TX_COMPLETE +} sahara_packet_done_resp; + +// RESET packet type - sent from host to target +// indicates to target to reset +typedef struct +{ + sahara_packet_header header; +} sahara_packet_reset; + +// RESET_RESP packet type - sent from target to host +// indicates to host that target has reset +typedef struct +{ + sahara_packet_header header; +} sahara_packet_reset_resp; +#endif /* SAHARA_PACKET_H */ diff --git a/rooter/0optionalapps/qfirehose/src/stream_download_protocol.c b/rooter/0optionalapps/qfirehose/src/stream_download_protocol.c new file mode 100644 index 0000000..1033565 --- /dev/null +++ b/rooter/0optionalapps/qfirehose/src/stream_download_protocol.c @@ -0,0 +1,766 @@ +/****************************************************************************** + @file stream_download_protocol.c + @brief stream protocol. + + DESCRIPTION + QFirehoe Tool for USB and PCIE of Quectel wireless cellular modules. + + INITIALIZATION AND SEQUENCING REQUIREMENTS + None. + + --------------------------------------------------------------------------- + Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved. + Quectel Wireless Solution Proprietary and Confidential. + --------------------------------------------------------------------------- +******************************************************************************/ + +#include "usb_linux.h" +#include "hostdl_packet.h" + +#define true (1==1) +#define false (1!=1) + +#define MAX_SEND_BUFFER_SIZE 1280 +#define MAX_RECEIVE_BUFFER_SIZE 1280 +unsigned char g_Transmit_Buffer[MAX_SEND_BUFFER_SIZE]; +int g_Transmit_Length; + +unsigned char g_Receive_Buffer[MAX_RECEIVE_BUFFER_SIZE]; +int g_Receive_Bytes; + +static void *stream_usb_handle; + +static void dump_buffer(unsigned char * buff, int len) +{ + int i = 0; + + dbg_time("dump buffer: %d bytes\n", len); + for(i = 0; i < len; i++) + { + dbg_time("%02x ", buff[i]); + } + dbg_time("\nend\n"); + +} + +#define CRC_16_L_SEED 0xFFFF +#define CRC_TAB_SIZE 256 /* 2^CRC_TAB_BITS */ +#define CRC_16_L_POLYNOMIAL 0x8408 + +static const uint16_t crc_16_l_table[ CRC_TAB_SIZE ] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +unsigned short crc_16_l_calc(unsigned char *buf_ptr, int len) { + int data, crc_16; + for (crc_16 = CRC_16_L_SEED; len >= 8; len -= 8, buf_ptr++) { + crc_16 = crc_16_l_table[(crc_16 ^ *buf_ptr) & 0x00ff] ^ (crc_16 >> 8); + } + if (len != 0) { + + data = ((int) (*buf_ptr)) << (16 - 8); + + while (len-- != 0) { + if (((crc_16 ^ data) & 0x01) != 0) { + + crc_16 >>= 1; + crc_16 ^= CRC_16_L_POLYNOMIAL; + + } else { + + crc_16 >>= 1; + + } + + data >>= 1; + } + } + return (~crc_16); +} + +void compute_reply_crc () +{ + unsigned short crc = crc_16_l_calc (g_Transmit_Buffer, g_Transmit_Length * 8); + g_Transmit_Buffer[g_Transmit_Length] = crc & 0xFF; + g_Transmit_Buffer[g_Transmit_Length + 1] = crc >> 8; + g_Transmit_Length += 2; +} + +static void compose_packet(unsigned char cmd, unsigned char *parameter, uint32_t parameter_len, unsigned char *data, uint32_t data_len) { + uint32_t i; + + g_Transmit_Buffer[0] = cmd; + if (parameter == NULL) parameter_len = 0; + if (data == NULL) data_len = 0; + for (i = 0; i < parameter_len; i++) { + g_Transmit_Buffer[1 + i] = parameter[i]; + } + for (i = 0; i < data_len; i++) { + g_Transmit_Buffer[1 + parameter_len + i] = data[i]; + } + g_Transmit_Length = 1 + parameter_len + data_len; + g_Transmit_Buffer[g_Transmit_Length] = 0; +} + +static unsigned char stream_tx_buf[1280]; +#define CHECK_FOR_DATA() do {} while(0) +#define TRANSMIT_BYTE(_byte) do { stream_tx_buf[j++] = _byte; } while(0) + +static int send_packet(int flag) { + int i; + int ch; + int j; + + j = 0; + + + CHECK_FOR_DATA (); + + /* Since we don't know how long it's been. */ + if (!!flag) { + TRANSMIT_BYTE (0x7E); + } + + for (i = 0; i < g_Transmit_Length; i++) + { + /* we only need to check once every 31 characters, since RX and TX + * run at about the same speed, and our RX FIFO is 64 characters + */ + if ((i & 31) == 31) + CHECK_FOR_DATA (); + + ch = g_Transmit_Buffer[i]; + + if (ch == 0x7E || ch == 0x7D) + { + TRANSMIT_BYTE (0x7D); + TRANSMIT_BYTE (0x20 ^ ch); /*lint !e734 */ + } + else + { + TRANSMIT_BYTE (ch); /*lint !e734 */ + } + } + + CHECK_FOR_DATA (); + TRANSMIT_BYTE (0x7E); + +#if 0 + /* Hack for USB protocol. If we have an exact multiple of the USB frame + * size, then the last frame will not be sent out. The USB standard says + * that a "short packet" needs to be sent to flush the data. Two flag + * characters can serve as the short packet. Doing it this way, we only + * perform this test once on every entire packet from the target, so the + * over head is not too much. + */ + if ((j%512) == 0) + { + TRANSMIT_BYTE (0x7E); + TRANSMIT_BYTE (0x7E); + } + #endif + + return (qusb_noblock_write(stream_usb_handle, stream_tx_buf, j, j, 3000, 1) == j) ? 0 : -1; +} + +static int remove_escape_hdlc_flag(unsigned char* buffer, int len) +{ + int i = 0; + int index = 0; + int escape = 0; + //dump_buffer(buffer, len); + if(len == 0) return 0; + //ignore the first HDLC FLAG bytes + while(buffer[i] == 0x7e) + { + i++; + } + //all bytes is HDLC FLAG + if(i == len) + return 0; + for(; i < len; i++) + { + if(buffer[i] == 0x7D) + { + escape = 1; + continue; + } + if(escape == 1) + { + escape = 0; + buffer[i] ^= 0x20; + } + buffer[index++] = buffer[i]; + } + buffer[index] = 0; + //dump_buffer(buffer, index); + return index; +} + +static int receive_packet(void) +{ + int bytesread = 0; + unsigned char *buff = g_Receive_Buffer; + int idx = 0; + do + { + bytesread = qusb_noblock_read(stream_usb_handle, &buff[idx], MAX_RECEIVE_BUFFER_SIZE, 0, 3000); + if(bytesread == 0) + { + //timeout may be error + dbg_time("%s timeout\n", __FUNCTION__); + return 0; + } + //dump_buffer(&buff[idx], bytesread); + idx += bytesread; + if(buff[idx - 1] == 0x7e) + { + //check the packet whether valid. + g_Receive_Bytes = remove_escape_hdlc_flag(buff, idx); + if(g_Receive_Bytes == 0) + { + continue; + }else{ + return 1; + } + } + }while(1); + + return 0; +} + +static int handle_hello(void) +{ + static const char host_header[] = "QCOM fast download protocol host"; + //static const char target_header[] = "QCOM fast download protocol targ"; + //char string1[64]; + //int size; + int err; + dbg_time("%s\n", __func__); + + memset(&g_Transmit_Buffer[0],0,sizeof(g_Transmit_Buffer)); + g_Transmit_Buffer[HELLO_CMD_OFFSET] = HELLO_REQ; + memcpy(&g_Transmit_Buffer[HELLO_MAGIC_NUM_OFFSET],host_header,32); + g_Transmit_Buffer[HELLO_MAX_VER_OFFSET] = STREAM_DLOAD_MAX_VER; + g_Transmit_Buffer[HELLO_MIN_VER_OFFSET] = STREAM_DLOAD_MIN_VER; + g_Transmit_Buffer[HELLO_MAX_DATA_SZ_1_OFFSET] = 0; + g_Transmit_Length = 36; + + compute_reply_crc(); + send_packet(1); + + int timeout = 5; + do{ + err = receive_packet(); + if(err == 1){ + switch(g_Receive_Buffer[0]) + { + case 0x02: + return 1; + case 0x0d: + continue; + default: + //dump_buffer(g_Receive_Buffer, 64); + return 0; + } + } + else if(err == -1){ + dbg_time("error = %d, strerr = %s\n", errno, strerror(errno)); + return 0; + } + timeout--; + }while(timeout); + + return 0; +} + +static int handle_security_mode(unsigned char trusted) { + dbg_time("%s trusted = %d\n", __func__, trusted); + compose_packet(0x17, &trusted, 1, NULL, 0); + compute_reply_crc(); + send_packet(1); + int timeout = 5; + do{ + if(receive_packet() == 1){ + switch(g_Receive_Buffer[0]) + { + case 0x18: + return 1; + default: + return 0; + } + }else + { + timeout--; + if(timeout==0) + { + dbg_time("%s timeout\n", __FUNCTION__); + return 0; + } + } + }while(1); + return 0; +} +/* +set download flag in module, quectel custom command, +if flag : reboot, module will enter DM +if not flag: reboot normal +*/ +static int handle_quectel_download_flag(unsigned char mode) { + //byte mode = 1; + compose_packet(0x60, &mode, 1, NULL, 0); + compute_reply_crc(); + send_packet(1); + int timeout = 5; + do{ + if(receive_packet() == 1) + { + switch(g_Receive_Buffer[0]) + { + case 0x61: + switch( g_Receive_Buffer[1] ) + { + case 0x00: + return 1; + default: + return 0; + } + break; + case 0x0E: + dbg_time("Invalid command"); + return 2; + default: + dump_buffer(g_Receive_Buffer, 64); + return 0; + } + } + else + { + timeout--; + if(timeout==0) + { + dbg_time("%s timeout\n", __FUNCTION__); + return 0; + } + } + }while(1); +} + +static const char *stream_firehose_dir; +static int stread_fread(const char *filename, void **pp_filebuf) { + int filesize = 0; + FILE *fp; + char fullpath[MAX_PATH*2]; + + snprintf(fullpath, sizeof(fullpath), "%.240s/../%.240s", stream_firehose_dir, filename); + fp = fopen(fullpath, "rb"); + if (fp == NULL) { + dbg_time("fail to fope %s, errno: %d (%s)\n", fullpath, errno, strerror(errno)); + return 0; + } + + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + + *pp_filebuf = malloc(filesize); + fseek(fp, 0, SEEK_SET); + filesize = fread(*pp_filebuf, 1, filesize, fp); + fclose(fp); + + dbg_time("%s filename=%s, filesize=%d\n", __func__, filename, filesize); + return filesize; +} + +static int handle_parti_tbl(unsigned char override) { + int timeout = 5; + int filesize; + void *filebuf; + const char *partition_path= "partition.mbn"; + dbg_time("%s override = %d\n", __func__, override); + + filesize = stread_fread(partition_path, &filebuf); + if (filesize <= 0) + return 0; + + compose_packet(0x19, &override, 1, filebuf, filesize); + compute_reply_crc(); + send_packet(1); + free(filebuf); + + do{ + if(receive_packet() == 1){ + dbg_time("handle_parti_tbl command = %02x, status = %02x\n", g_Receive_Buffer[0], g_Receive_Buffer[1]); + switch(g_Receive_Buffer[0]) + { + case 0x1a: + switch( g_Receive_Buffer[1] ){ + case 0x00: + return 1; + case 0x01: //0x1 this means that the original partition is different from the current partition,try to send partition + return 0; + case 0x02: //0x2 Partition table format not recognized, does not accept override + return 0; + case 0x03: //0x3 Erase operation failed + return 0; + break; + default: + return 0; + } + default: + return 0; + } + }else + { + timeout--; + if(timeout == 0) + { + dbg_time("%s timeout\n", __FUNCTION__); + return 0; + } + } + }while(1); +} + +static int handle_reset(void) { + dbg_time("%s\n", __func__); + compose_packet(0x0b, NULL, 0, NULL, 0); + compute_reply_crc(); + send_packet(1); +#if 1 + return 1; +#else + int timeout = 5; + do{ + if(receive_packet() == 1){ + switch(g_Receive_Buffer[0]) + { + case 0x0c: + return 1; + case 0x0d: + continue; + default: + dump_buffer(g_Receive_Buffer, 64); + return 0; + } + } + else + { + + timeout--; + if(timeout == 0) + { + dbg_time("%s timeout\n", __FUNCTION__); + return 0; + } + } + }while(1); +#endif +} + +/******pkt_open_multi_image*******/ + +static void pkt_open_multi_image (unsigned char mode, unsigned char *data, uint32_t size) { + compose_packet(0x1b, &mode, 1, data, size); + compute_reply_crc(); +} + +static int handle_openmulti(uint32_t size,unsigned char* data) +{ + int timeout = 5; + unsigned char mode=0x0e; + + pkt_open_multi_image(mode, data, size); + send_packet(1); + do { + if (receive_packet() == 1) { + switch (g_Receive_Buffer[0]) { + case 0x1c: + return 1; + case 0x0d: + continue; + default: + return 0; + } + }else + { + + timeout--; + if(timeout == 0) + { + dbg_time("%s timeout\n", __FUNCTION__); + return 0; + } + } + } while (1); + return 1; +} + +/******pkt_write_multi_image*******/ +static void pkt_write_multi_image(uint32_t addr, unsigned char*data, uint16_t size) { + unsigned char parameter[4] = {(unsigned char)(addr)&0xff, (unsigned char)(addr>>8)&0xff, (unsigned char)(addr>>16)&0xff, (unsigned char)(addr>>24)&0xff}; + compose_packet(0x07, parameter, 4, data, size); + compute_reply_crc(); +} + +static int handle_write(unsigned char *data, uint32_t size) +{ + //uint32_t total_size; + uint32_t addr = 0; + uint32_t writesize; + uint32_t buffer_size = 1024; + //int loop = 1; + int retry_cnt = 3; //if send failed,send again + int ret; + + //total_size = size; + while(size) + { + writesize = (size < buffer_size) ? size : buffer_size; + + pkt_write_multi_image(addr, data, writesize); +start_send_packet: + ret = send_packet(1); + if(0 != ret) + { + dbg_time("io read/write failed\n"); + return 0; + } + if(receive_packet() == 1){ + switch(g_Receive_Buffer[0]) + { + case 0x08: + size -= writesize; + addr += writesize; + //retry_cnt=5; + break; + default: + goto retry_send_packet; + return 0; + } + } + else + { + +retry_send_packet: + retry_cnt--; + if(retry_cnt > 0) + { + goto start_send_packet; + } + else + { + dbg_time( "value is [0x%02x]",g_Receive_Buffer[0]); + return 0; + } + } + + } + + return 1; +} +/******PARTITION*******/ +static int handle_close(void) { + int timeout = 5; + compose_packet(0x15, NULL, 0, NULL, 0); + compute_reply_crc(); + send_packet(1); + + do{ + if(receive_packet() == 1){ + switch(g_Receive_Buffer[0]) + { + case 0x16: + return 1; + default: + return 0; + } + }else + { + + timeout--; + if(timeout == 0) + { + dbg_time("%s timeout\n", __FUNCTION__); + return 0; + } + } + }while(1); + return 0; +} + +static int do_flash_mbn(const char *partion, const char *filepath) { + int result = false; + void *filebuf = NULL; + int filesize = 0; + + dbg_time("%s %s\n", __func__, partion); + + if (filepath) { + filesize = stread_fread(filepath, &filebuf); + if (filesize <= 0) + return 0; + } + else { + filesize = 4*1024; + filebuf = (unsigned char *)malloc(filesize); + memset(filebuf, 0x00, filesize); + } + + result = handle_openmulti(strlen(partion) + 1, (unsigned char *)partion); + if (result == false) { + dbg_time("%s open failed\n", partion); + goto __fail; + } + + dbg_time("sending '%s' (%dKB)\n", partion, (int)(filesize/1024)); + + result = handle_write(filebuf, filesize); + if (result == false) { + dbg_time("%s download failed\n", partion); + goto __fail; + } + + result = handle_close(); + if (result == false) { + dbg_time("%s close failed.\n", partion); + goto __fail; + } + + dbg_time("OKAY\n"); + +__fail: + free(filebuf); + + return result; +} + +int stream_download(const char *firehose_dir, void *usb_handle, unsigned qusb_zlp_mode) +{ + (void)qusb_zlp_mode; + stream_usb_handle = usb_handle; + stream_firehose_dir = firehose_dir; + + if (handle_hello() == false) { + dbg_time("Send hello command fail\n"); + return false; + } + + /* + hello packet will set dload flag in module, when upgrade interrup, restart module,module will enter dm(quectel sbl) + */ + if (handle_security_mode(1) == false) { + dbg_time("Send trust command fail\n"); + return false; + } + + if (handle_parti_tbl(0) == false) { + dbg_time("----------------------------------\n"); + dbg_time("Detect partition mismatch.\n"); + dbg_time("Download parition with override.\n"); + dbg_time("----------------------------------\n"); + + if(handle_parti_tbl(1) == false) { + dbg_time("override failed. \n"); + return false; + } + + /* + partition is not match, the download flag will be clear, so set it again, reset will clear it + */ + if(handle_quectel_download_flag(1) == false) { + dbg_time("Set Quectel download flag failed\n"); + } + else { + dbg_time("Set Quectel download flag successfully\n"); + } + } + +#if 1 + if (do_flash_mbn("0:SBL", "sbl1.mbn") == false) { + return false; + } +#endif + + if (handle_reset() == false) { + dbg_time("Send reset command failed\n"); + return false; + } + + dbg_time("%s successful\n", __func__); + + return true; +} + +//hunter.lv add +//retrieve module soft revision + +typedef struct +{ + unsigned char cmd_code; + unsigned char version; + unsigned char reserved[2]; + unsigned char msm[4]; + unsigned char mobile_modle_number[4]; + unsigned char mobile_software_revision[1]; +}__attribute__ ((packed))extended_build_id_response_t; + +int retrieve_soft_revision(void *usb_handle, uint8_t *mobile_software_revision, unsigned length) +{ +/* +80-v1294-1_yyd_serial_interface_control_document_(icd)_for_cdma_dual-mode_subscriber_station_data 3.4.122 Extended Build ID +*/ + uint8_t req1[] = {0x7E,0x7C, 0x93,0x49, 0x7E}; + int ret; + uint8_t *rx_buff = malloc(2048); + + memset(mobile_software_revision, 0x00, length); + + if (rx_buff == NULL) + return 0; + + ret = qusb_noblock_write(usb_handle, req1, sizeof(req1), sizeof(req1), 1000, 0); + if(ret > 0) { + ret = qusb_noblock_read(usb_handle, rx_buff , 2048, 1, 3000); + if (ret > 0) { + if (rx_buff[0] == 0x7C && rx_buff[ret - 1] == 0x7E) { + extended_build_id_response_t *rsp = (extended_build_id_response_t *)rx_buff; + (void)length; + memcpy(mobile_software_revision, rsp->mobile_software_revision, strlen((const char *)rsp->mobile_software_revision)); + } + } + } + + free(rx_buff); + return (mobile_software_revision[0] != '\0'); +} diff --git a/rooter/0optionalapps/qfirehose/src/usb2tcp.c b/rooter/0optionalapps/qfirehose/src/usb2tcp.c new file mode 100644 index 0000000..0d8e4d3 --- /dev/null +++ b/rooter/0optionalapps/qfirehose/src/usb2tcp.c @@ -0,0 +1,338 @@ +/****************************************************************************** + @file tty2tcp.c + @brief switch data between tcp socket and ttyUSB port. + + DESCRIPTION + QLog Tool for USB and PCIE of Quectel wireless cellular modules. + + INITIALIZATION AND SEQUENCING REQUIREMENTS + None. + + --------------------------------------------------------------------------- + Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved. + Quectel Wireless Solution Proprietary and Confidential. + --------------------------------------------------------------------------- +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) +#include +#else +#include +#endif +//#include +#include "usb_linux.h" +#include //for __BYTE_ORDER +char *inet_ntoa(struct in_addr in); + +#define dprintf dbg_time + +#define MIN(a,b) ((a) < (b)? (a) : (b)) + +#define MAX_USBFS_BULK_IN_SIZE (4 * 1024) +#define MAX_USBFS_BULK_OUT_SIZE (16 * 1024) + +static uint32_t cpu_to_le32 (uint32_t v32) { + uint32_t tmp = v32; +#if __BYTE_ORDER == __LITTLE_ENDIAN +#else + unsigned char *s = (unsigned char *)(&v32); + unsigned char *d = (unsigned char *)(&tmp); + d[0] = s[3]; + d[1] = s[2]; + d[2] = s[1]; + d[3] = s[0]; +#endif + return tmp; +} +#define le32_to_cpu(_v32) cpu_to_le32(_v32) + +static int qusb_control[2]; + +static int noblock_full_read(int fd, void *pbuf, ssize_t size) { + ssize_t cur = 0; + + while (cur < size) { + ssize_t ret = read(fd, (char *)pbuf+cur, size-cur); + + if (ret > 0) + cur += ret; + else if (ret < 0 && errno == EAGAIN) { + struct pollfd pollfds[] = {{fd, POLLIN, 0}}; + poll(pollfds, 1, -1); + if (pollfds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) + break; + } else { + dprintf("fd=%d read=%zd, errno: %d (%s)\n", fd, ret, errno, strerror(errno)); + break; + } + } + + if (cur != size) { + dprintf("%s fd=%d cur=%zd, size=%zd\n", __func__, fd, cur, size); + } + + return cur; +} + +static ssize_t noblock_full_write(int fd, const void *pbuf, ssize_t size) { + ssize_t cur = 0; + + while (cur < size) { + ssize_t ret = write(fd, (char *)pbuf+cur, size-cur); + if (ret > 0) + cur += ret; + else if (ret <= 0 && errno == EAGAIN) { + struct pollfd pollfds[] = {{fd, POLLOUT, 0}}; + poll(pollfds, 1, -1); + if (pollfds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) + break; + } else { + dprintf("fd=%d write=%zd, errno: %d (%s)\n", fd, ret, errno, strerror(errno)); + break; + } + } + + if (cur != size) { + dprintf("%s fd=%d cur=%zd, size=%zd\n", __func__, fd, cur, size); + } + + return cur; +} + +static void* usb_bulk_read_thread(void* arg) { + const void *usb_handle = arg; + void *buf = malloc(MAX_USBFS_BULK_IN_SIZE); + int fd = qusb_control[1]; + + if (buf == NULL) + return NULL; + + while(usb_handle) { + int count = qusb_noblock_read(usb_handle, buf, MAX_USBFS_BULK_IN_SIZE, 1, 30000); + + if (count > 0) { + count = write(fd, buf, count); + count = read(fd, buf, 32); //wait usb2tcp_main read + if (count <= 0) { + dprintf("read=%d\n", count); + break; + } + } else if (count <= 0) { + break; + } + } + + close(fd); + free(buf); + return NULL; +} + +static int qusb_open(const void *usb_handle) { + int fd = -1; + pthread_t thread_id; + + pthread_attr_t usb_thread_attr; + pthread_attr_init(&usb_thread_attr); + pthread_attr_setdetachstate(&usb_thread_attr, PTHREAD_CREATE_DETACHED); + + socketpair(AF_LOCAL, SOCK_STREAM, 0, qusb_control); + pthread_create(&thread_id, &usb_thread_attr, usb_bulk_read_thread, (void*)usb_handle); + + fd = qusb_control[0]; + + return fd; +} + +static ssize_t qusb_read(int fd, void* pbuf, size_t size) { + return read(fd, pbuf, size); +} + +static int create_tcp_server(int socket_port) { + int sockfd = -1; + int reuse_addr = 1; + struct sockaddr_in sockaddr; + + dprintf("%s tcp_port=%d\n", __func__, socket_port); + /*Create server socket*/ + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd <= 0) + return sockfd; + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); + sockaddr.sin_port = htons(socket_port); + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr)); + if (bind(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { + close(sockfd); + dprintf("%s bind %d errno: %d (%s)\n", __func__, socket_port, errno, strerror(errno)); + return -1; + } + + return sockfd; +} + +static int wait_client_connect(int server_fd) { + int client_fd = -1; + unsigned char addr[128]; + socklen_t alen = sizeof(addr); + + dprintf("%s\n", __func__); + listen(server_fd, 1); + client_fd = accept(server_fd, (struct sockaddr *)addr, &alen); + if (client_fd <= 0) + return client_fd; + + if (client_fd > 0) { + struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; + dprintf("clientfd = %d %s:%d connect\n", client_fd, inet_ntoa(addr_in->sin_addr), addr_in->sin_port); + } + + return client_fd; +} + +int usb2tcp_main(const void *usb_handle, int tcp_port, unsigned qusb_zlp_mode) { + void *pbuf = malloc(MAX_USBFS_BULK_OUT_SIZE); + int server_fd = -1, client_fd = -1, usb_fd = -1, size = -1; + TLV_USB tlv_usb; + + if (pbuf == NULL) + return -1; + + server_fd = create_tcp_server(tcp_port); + dprintf("server_fd=%d\n", server_fd); + if (server_fd <= 0) { + dprintf("Fail create_tcp_server\n"); + goto _out; + } + + if (client_fd <= 0) { + client_fd = wait_client_connect(server_fd); + if (client_fd < 0) { + dprintf("Fail wait_client_connect\n"); + goto _out; + } + } + + usb_fd = qusb_open(usb_handle); + dprintf("usb_fd = %d\n", usb_fd); + + tlv_usb.tag = cpu_to_le32(Q_USB2TCP_VERSION); + tlv_usb.length = cpu_to_le32(12); + tlv_usb.idVendor = cpu_to_le32(0x05c6); + tlv_usb.idProduct = cpu_to_le32(0x9008); + tlv_usb.interfaceNum = cpu_to_le32(1); + if (write(client_fd, &tlv_usb, sizeof(tlv_usb)) == -1) {}; + + fcntl(usb_fd, F_SETFL, fcntl(usb_fd,F_GETFL) | O_NONBLOCK); + fcntl(client_fd, F_SETFL, fcntl(client_fd,F_GETFL) | O_NONBLOCK); + + while (usb_fd > 0 && client_fd > 0) { + struct pollfd pollfds[] = {{usb_fd, POLLIN, 0}, {client_fd, POLLIN, 0}}; + int ne, ret, nevents = sizeof(pollfds)/sizeof(pollfds[0]); + + do { + ret = poll(pollfds, nevents, -1); + } while (ret < 0 && errno == EINTR); + + + if (ret <= 0) { + dprintf("%s poll=%d, errno: %d (%s)\n", __func__, ret, errno, strerror(errno)); + goto _hangup; + } + + + if (pollfds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { + dprintf("%s poll usb_fd = %d, revents = %04x\n", __func__, usb_fd, pollfds[0].revents); + goto _hangup; + } + + + if (pollfds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) { + dprintf("%s poll client_fd = %d, revents = %04x\n", __func__, client_fd, pollfds[1].revents); + goto _hangup; + } + + for (ne = 0; ne < nevents; ne++) { + int fd = pollfds[ne].fd; + TLV tlv = {Q_USB2TCP_VERSION, 0}; + + if ((pollfds[ne].revents & POLLIN) == 0) + continue; + + if (fd == usb_fd) { + size = qusb_read(usb_fd, pbuf, MAX_USBFS_BULK_IN_SIZE); + if (size <= 0) { + dprintf("usb_fd=%d read=%d, errno: %d (%s)\n", fd, size, errno, strerror(errno)); + goto _hangup;; + } + if (write(usb_fd, pbuf, 1) == -1) {}; //wakeup usb_bulk_read_thread + + tlv.tag = cpu_to_le32(Q_USB2TCP_VERSION); + tlv.length = cpu_to_le32(size); + if (sizeof(tlv) != noblock_full_write(client_fd, &tlv, sizeof(tlv))) { + goto _hangup; + break; + } + + if (size != noblock_full_write(client_fd, pbuf, size)) { + goto _hangup; + break; + } + } + else if (fd == client_fd) { + size = noblock_full_read(client_fd, &tlv, sizeof(tlv)); + if (size != sizeof(tlv)) { + dprintf("client_fd=%d read=%d, errno: %d (%s)\n", fd, size, errno, strerror(errno)); + goto _hangup; + } + + if (le32_to_cpu(tlv.tag) != Q_USB2TCP_VERSION) { + break; + } + + size = le32_to_cpu(tlv.length); + if (size != noblock_full_read(client_fd, pbuf, size)) { + goto _hangup; + break; + } + qusb_noblock_write(usb_handle, pbuf, size, size, 3000, qusb_zlp_mode); + } + } + } + +_hangup: + if (usb_fd > 0) { + close(usb_fd); + usb_fd = -1; + } + if (client_fd > 0) { + close(client_fd); + client_fd = -1; + } + +_out: + free(pbuf); + return 0; +} diff --git a/rooter/0optionalapps/qfirehose/src/usb_linux.c b/rooter/0optionalapps/qfirehose/src/usb_linux.c new file mode 100644 index 0000000..9aa2ed8 --- /dev/null +++ b/rooter/0optionalapps/qfirehose/src/usb_linux.c @@ -0,0 +1,1170 @@ +/****************************************************************************** + @file usb_linux.c + @brief read and write usb devices. + + DESCRIPTION + QFirehoe Tool for USB and PCIE of Quectel wireless cellular modules. + + INITIALIZATION AND SEQUENCING REQUIREMENTS + None. + + --------------------------------------------------------------------------- + Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved. + Quectel Wireless Solution Proprietary and Confidential. + --------------------------------------------------------------------------- +******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) +#include +#else +#include +#endif +#include +#include +#include +#include "usb_linux.h" + +int edl_pcie_mhifd = -1; +int switch_to_edl_mode(void *usb_handle); + +extern uint32_t inet_addr(const char *); + +#define MAX_USBFS_BULK_IN_SIZE (4 * 1024) +#define MAX_USBFS_BULK_OUT_SIZE (16 * 1024) +#define EC20_MAX_INF 4 +#define MKDEV(__ma, __mi) (((__ma & 0xfff) << 8) | (__mi & 0xff) | ((__mi & 0xfff00) << 12)) + +struct quectel_usb_device { + char devname[64]; + int desc; + int ttyfd; + int idVendor; + int idProduct; + uint8_t bNumInterfaces; + uint8_t intr_ep[EC20_MAX_INF]; + uint8_t bulk_ep_in[EC20_MAX_INF]; + uint8_t bulk_ep_out[EC20_MAX_INF]; + int wMaxPacketSize[EC20_MAX_INF]; + int control[EC20_MAX_INF][2]; +}; + +static struct quectel_usb_device quectel_9x07; +static int tcp_socket_fd = -1; +static int usb_dm_interface = 0; + +static int strStartsWith(const char *line, const char *prefix) +{ + for ( ; *line != '\0' && *prefix != '\0' ; line++, prefix++) { + if (*line != *prefix) { + return 0; + } + } + + return *prefix == '\0'; +} + +static int quectel_get_sysinfo_by_uevent(const char *uevent, MODULE_SYS_INFO *pSysInfo) { + FILE *fp; + char line[MAX_PATH]; + + memset(pSysInfo, 0x00, sizeof(MODULE_SYS_INFO)); + + fp = fopen(uevent, "r"); + if (fp == NULL) { + dbg_time("fail to fopen %s, errno: %d (%s)\n", uevent, errno, strerror(errno)); + return 0; + } + + //dbg_time("%s\n", uevent); + while (fgets(line, sizeof(line), fp)) { + if (line[strlen(line) - 1] == '\n' || line[strlen(line) - 1] == '\r') { + line[strlen(line) - 1] = '\0'; + } + + //dbg_time("%s\n", line); + if (strStartsWith(line, "MAJOR=")) { + pSysInfo->MAJOR = atoi(&line[strlen("MAJOR=")]); + } + else if (strStartsWith(line, "MINOR=")) { + pSysInfo->MINOR = atoi(&line[strlen("MINOR=")]); + } + else if (strStartsWith(line, "DEVNAME=")) { + if(pSysInfo) + strncpy(pSysInfo->DEVNAME, &line[strlen("DEVNAME=")], sizeof(pSysInfo->DEVNAME)); + } + else if (strStartsWith(line, "DEVTYPE=")) { + strncpy(pSysInfo->DEVTYPE, &line[strlen("DEVTYPE=")], sizeof(pSysInfo->DEVTYPE)); + } + else if (strStartsWith(line, "PRODUCT=")) { + strncpy(pSysInfo->PRODUCT, &line[strlen("PRODUCT=")], sizeof(pSysInfo->PRODUCT)); + } + } + + fclose(fp); + + return 1; +} + +// the return value is the number of quectel modules +int auto_find_quectel_modules(char *module_sys_path, unsigned size) +{ + const char *base = "/sys/bus/usb/devices"; + DIR *busdir = NULL; + struct dirent *de = NULL; + int count = 0; + + busdir = opendir(base); + if (busdir == NULL) + return -1; + + while ((de = readdir(busdir))) { + static char uevent[MAX_PATH]; + static MODULE_SYS_INFO sysinfo; + + if (!isdigit(de->d_name[0])) continue; + + snprintf(uevent, sizeof(uevent), "%.24s/%.16s/uevent", base, de->d_name); + if (!quectel_get_sysinfo_by_uevent(uevent, &sysinfo)) + continue; + + if (sysinfo.MAJOR != 189) + continue; + + //dbg_time("MAJOR=%d, MINOR=%d, DEVNAME=%s, DEVTYPE=%s, PRODUCT=%s\n", + // sysinfo.MAJOR, sysinfo.MINOR, sysinfo.DEVNAME, sysinfo.DEVTYPE, sysinfo.PRODUCT); + + if (sysinfo.DEVTYPE[0] == '\0' || strStartsWith(sysinfo.DEVTYPE, "usb_device") == 0) + continue; + + if (sysinfo.PRODUCT[0] == '\0') { + continue; + } + + if (!(strStartsWith(sysinfo.PRODUCT, "2c7c/") + || strStartsWith(sysinfo.PRODUCT, "5c6/9008") + || strStartsWith(sysinfo.PRODUCT, "5c6/901f") + || strStartsWith(sysinfo.PRODUCT, "5c6/9091") + || strStartsWith(sysinfo.PRODUCT, "3763/3c93/318"))) { + continue; + } + + if ((strStartsWith(sysinfo.PRODUCT, "2c7c/6") || strStartsWith(sysinfo.PRODUCT, "2c7c/8")) + && (sysinfo.PRODUCT[strlen("2c7c/6000")] == '/')) //skip ASR&HISI modules + continue; + + snprintf(module_sys_path, size, "%.24s/%s", base, de->d_name); + count++; + dbg_time("[%d] %s %s\n", count, module_sys_path, sysinfo.PRODUCT); + } + + closedir(busdir); + + return count; +} + +void quectel_get_ttyport_by_syspath(const char *module_sys_path, char *module_port_name, unsigned size) { + char infname[256]; + DIR *infdir = NULL; + struct dirent *de = NULL; + + module_port_name[0] = '\0'; + + sprintf(infname, "%s:1.%d", module_sys_path, usb_dm_interface); + infdir = opendir(infname); + if (infdir == NULL) + return; + + while ((de = readdir(infdir))) { + if (strStartsWith(de->d_name, "ttyUSB")) { + snprintf(module_port_name, size, "/dev/%s", de->d_name); + break; + } + else if (!strncmp(de->d_name, "tty", strlen("tty"))) { + sprintf(infname, "%s:1.%d/tty", module_sys_path, usb_dm_interface); + closedir(infdir); + infdir = opendir(infname); + if (infdir == NULL) + break; + } + } + + if (infdir) closedir(infdir); +} + +static void quectel_fixup_sysport(const char *module_port_name, char *sysport, unsigned size) { + char syspath[MAX_PATH+16]; + const char *sys_base = "/sys/class/tty"; + DIR *sys_dir = NULL; + struct dirent *dev = NULL; + + sysport[0] = '\0'; + sys_dir = opendir(sys_base); + if (!sys_dir) { + dbg_time("fail to opendir('%s'), errno: %d (%s)\n", sys_base, errno, strerror(errno)); + return; + } + + while (NULL != (dev = readdir(sys_dir))) + { + if (!strncasecmp("ttyUSB", dev->d_name, strlen("ttyUSB"))) { + MODULE_SYS_INFO sysinfo; + + snprintf(syspath, sizeof(syspath), "%.24s/%.16s/uevent", sys_base, dev->d_name); + if (quectel_get_sysinfo_by_uevent(syspath, &sysinfo)) { + struct stat buf; + dev_t devt; + + devt = makedev(sysinfo.MAJOR, sysinfo.MINOR); + if(!stat(module_port_name, &buf) && buf.st_rdev == devt) { + snprintf(sysport, size, "/sys/class/tty/%.16s", dev->d_name); + break; + } + } + } + } + closedir(sys_dir); +} + + +void quectel_get_syspath_name_by_ttyport(const char *module_port_name, char *module_sys_path, unsigned size) { + char syspath[MAX_PATH]; + char sysport[64]; + int count; + char *pchar = NULL; + char dm_tty[24]; + + snprintf(dm_tty, sizeof(dm_tty), ":1.%d/tty", usb_dm_interface); + module_sys_path[0] = '\0'; + + snprintf(sysport, sizeof(sysport), "/sys/class/tty/%.48s", &module_port_name[strlen("/dev/")]); + if(access(sysport, F_OK) && errno == ENOENT) { + quectel_fixup_sysport(module_port_name, sysport, sizeof(sysport));//query real name + } + if(access(sysport, F_OK) && errno == ENOENT) + return; + count = readlink(sysport, syspath, sizeof(syspath) - 1); + if (count < (int)strlen(dm_tty)) + return; + +//ttyUSB0 -> ../../devices/soc0/soc/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1/1-1/1-1:1.0/ttyUSB0/tty/ttyUSB0 + pchar = strstr(syspath, dm_tty); + if (pchar == NULL) + return; + + *pchar = '\0'; + while (*pchar != '/') + pchar--; + + snprintf(module_sys_path, size, "/sys/bus/usb/devices/%.232s", pchar + 1); +} + +static void quectel_get_usb_device_info(const char *module_sys_path, struct quectel_usb_device *udev) { + static unsigned char devdesc[1024]; + size_t desclength, len; + char devname[MAX_PATH]; + int desc_fd; + __u8 bInterfaceNumber = 0; + int dev_mknod_and_delete_after_use = 0; + + MODULE_SYS_INFO sysinfo; + snprintf(devname, sizeof(devname), "%.248s/%s", module_sys_path, "uevent"); + if (!quectel_get_sysinfo_by_uevent(devname, &sysinfo)) + return; + + snprintf(devname, sizeof(devname), "/dev/%s", sysinfo.DEVNAME); + if (access(devname, R_OK) && errno_nodev()) { + //maybe Linux have create /sys/ device, but not ready to create /dev/ device. + usleep(100*1000); + } + + if (access(devname, R_OK) && errno_nodev()) + { + char *p = strstr(devname+strlen("/dev/"), "/"); + + while (p) { + p[0] = '_'; + p = strstr(p, "/"); + } + + if (mknod(devname, S_IFCHR|0666, MKDEV(sysinfo.MAJOR, sysinfo.MINOR))) { + devname[1] = 't'; + devname[2] = 'm'; + devname[3] = 'p'; + + if (mknod(devname, S_IFCHR|0666, MKDEV(sysinfo.MAJOR, sysinfo.MINOR))) { + dbg_time("Fail to mknod %s, errno : %d (%s)\n", devname, errno, strerror(errno)); + return; + } + } + + dev_mknod_and_delete_after_use = 1; + } + + desc_fd = open(devname, O_RDWR | O_NOCTTY); + + if (dev_mknod_and_delete_after_use) { + remove(devname); + } + + if (desc_fd <= 0) { + dbg_time("fail to open %s, errno: %d (%s)\n", devname, errno, strerror(errno)); + return; + } + + desclength = read(desc_fd, devdesc, sizeof(devdesc)); + len = 0; + while (len < desclength) { + struct usb_descriptor_header *h = (struct usb_descriptor_header *)(&devdesc[len]); + + if (h->bLength == sizeof(struct usb_device_descriptor) && h->bDescriptorType == USB_DT_DEVICE) { + struct usb_device_descriptor *device = (struct usb_device_descriptor *)h; + + udev->idVendor = device->idVendor; + udev->idProduct = device->idProduct; + dbg_time("P: %s idVendor=%04x idProduct=%04x\n", devname, device->idVendor, device->idProduct); + } + else if (h->bLength == sizeof(struct usb_config_descriptor) && h->bDescriptorType == USB_DT_CONFIG) { + struct usb_config_descriptor *config = (struct usb_config_descriptor *)h; + + dbg_time("C: %s bNumInterfaces: %d\n", devname, config->bNumInterfaces); + udev->bNumInterfaces = config->bNumInterfaces; + } + else if (h->bLength == sizeof(struct usb_interface_descriptor) && h->bDescriptorType == USB_DT_INTERFACE) { + struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)h; + + dbg_time("I: If#= %d Alt= %d #EPs= %d Cls=%02x Sub=%02x Prot=%02x\n", + interface->bInterfaceNumber, interface->bAlternateSetting, interface->bNumEndpoints, + interface->bInterfaceClass, interface->bInterfaceSubClass, interface->bInterfaceProtocol); + bInterfaceNumber = interface->bInterfaceNumber; + } + else if (h->bLength == USB_DT_ENDPOINT_SIZE && h->bDescriptorType == USB_DT_ENDPOINT) { + if (bInterfaceNumber < EC20_MAX_INF) { + struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)h; + + dbg_time("E: Ad=%02x Atr=%02x MxPS= %d Ivl=%dms\n", + endpoint->bEndpointAddress, endpoint->bmAttributes, endpoint->wMaxPacketSize, endpoint->bInterval); + + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { + if (endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + udev->bulk_ep_in[bInterfaceNumber] = endpoint->bEndpointAddress; + else + udev->bulk_ep_out[bInterfaceNumber] = endpoint->bEndpointAddress; + udev->wMaxPacketSize[bInterfaceNumber] = endpoint->wMaxPacketSize; + } else if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT){ + udev->intr_ep[bInterfaceNumber] = endpoint->bEndpointAddress; + } + } + } else { + } + + len += h->bLength; + } + + if (len == desclength) { + strcpy(udev->devname, devname); + udev->desc = desc_fd; + } + + usb_dm_interface = 0; + if ((udev->bulk_ep_in[usb_dm_interface] == 0 && udev->bulk_ep_in[usb_dm_interface] == 0) + || (udev->idVendor == 0x2c7c && udev->idProduct == 0x0127)) + usb_dm_interface = 3; +} + +static int usbfs_bulk_write(struct quectel_usb_device *udev, const void *data, int len, int timeout_msec, int need_zlp) { + struct usbdevfs_urb bulk; + struct usbdevfs_urb *urb = &bulk; + int n = -1; + int bInterfaceNumber = usb_dm_interface; + + (void)timeout_msec; + //if (urb->type == 0) + { + memset(urb, 0, sizeof(struct usbdevfs_urb)); + urb->type = USBDEVFS_URB_TYPE_BULK; + urb->endpoint = udev->bulk_ep_out[bInterfaceNumber]; + } + + urb->status = -1; + urb->buffer = (void *)data; + urb->buffer_length = (len > MAX_USBFS_BULK_OUT_SIZE) ? MAX_USBFS_BULK_OUT_SIZE : len; + urb->usercontext = urb; + + if ((len <= MAX_USBFS_BULK_OUT_SIZE) && need_zlp && (len%udev->wMaxPacketSize[bInterfaceNumber]) == 0) { + //dbg_time("USBDEVFS_URB_ZERO_PACKET\n"); +#ifndef USBDEVFS_URB_ZERO_PACKET +#define USBDEVFS_URB_ZERO_PACKET 0x40 +#endif + urb->flags = USBDEVFS_URB_ZERO_PACKET; + } else { + urb->flags = 0; + } + + do { + n = ioctl(udev->desc, USBDEVFS_SUBMITURB, urb); + } while((n < 0) && (errno == EINTR)); + + if (n != 0) { + dbg_time("inf[%d] USBDEVFS_SUBMITURB %d/%d, errno = %d (%s)\n", bInterfaceNumber, n, urb->buffer_length, errno, strerror(errno)); + return -1; + } + + do { + urb = NULL; + n = ioctl(udev->desc, USBDEVFS_REAPURB, &urb); + } while((n < 0) && (errno == EINTR)); + + if (n != 0) { + dbg_time("inf[%d] ep_out %d/%d, errno = %d (%s)\n", bInterfaceNumber, n, urb->buffer_length, errno, strerror(errno)); + } + + //dbg_time("[ urb @%p status = %d, actual = %d ]\n", urb, urb->status, urb->actual_length); + + if (urb && urb->status == 0 && urb->actual_length) + return urb->actual_length; + + return -1; +} + +static int poll_wait(int poll_fd, short events, int timeout_msec) { + struct pollfd pollfds[] = {{poll_fd, events, 0}}; + int ret; + + do { + ret = poll(pollfds, 1, timeout_msec); + } while(ret == -1 && errno == EINTR); + + if (ret == 1 && (pollfds[0].revents & (events))) + return 0; + else if (ret == 0) {//timeout + dbg_time("poll_wait events=%s msec=%d timeout\n", + (events & POLLIN) ? "POLLIN" : "POLLOUT", timeout_msec); + return ETIMEDOUT; + } + + return EIO; +} + +static int usbfs_bulk_read(struct quectel_usb_device *udev, void *pbuf, int len, int timeout) { + struct usbdevfs_bulktransfer bulk; + int n = -1; + int bInterfaceNumber = usb_dm_interface; + + if (len < 512) { + dbg_time("%s len=%d is too short\n", __func__, len); + return 0; + } + + bulk.ep = udev->bulk_ep_in[bInterfaceNumber]; + bulk.len = (len > MAX_USBFS_BULK_IN_SIZE) ? MAX_USBFS_BULK_IN_SIZE : len; + bulk.data = (void *)pbuf; + bulk.timeout = timeout; + + n = ioctl(udev->desc, USBDEVFS_BULK, &bulk); + if( n <= 0 ) { + if (errno == ETIMEDOUT) { + dbg_time("inf[%d] ep_in %d/%d, errno = %d (%s), timeout=%d\n", bInterfaceNumber, n, bulk.len, errno, strerror(errno), timeout); + n = 0; + } + else + dbg_time("inf[%d] ep_in %d/%d, errno = %d (%s)\n", bInterfaceNumber, n, bulk.len, errno, strerror(errno)); + } + + return n ; +} + +static int qtcp_connect(const char *port_name, int *idVendor, int *idProduct, int *interfaceNum) { + int fd = -1; + char *tcp_host = strdup(port_name); + char *tcp_port = strchr(tcp_host, ':'); + struct sockaddr_in sockaddr; + TLV_USB tlv_usb; + + dbg_time("%s port_name = %s\n", __func__, port_name); + + if (tcp_port == NULL) + return -1; + + *tcp_port++ = '\0'; + if (atoi(tcp_port) < 1 || atoi(tcp_port) > 0xFFFF) + return -1; + + fd = socket(AF_INET, SOCK_STREAM, 0); + + if (fd <= 0) { + dbg_time("Device could not be socket: Linux System Errno: %s\n", strerror (errno)); + return -1; + } + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_addr.s_addr = inet_addr(tcp_host); + sockaddr.sin_port = htons(atoi(tcp_port)); + + free(tcp_host); + if (connect(fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr)) < 0) { + close(fd); + dbg_time("Device could not be connect: Linux System Errno: %s\n", strerror (errno)); + return -1; + } + + //block read, untill usb2tcp tell me the usb device information + memset(&tlv_usb, 0x00, sizeof(tlv_usb)); + if (read(fd, &tlv_usb, sizeof(tlv_usb)) == -1) { }; + *idVendor = tlv_usb.idVendor; + *idProduct = tlv_usb.idProduct; + *interfaceNum = tlv_usb.interfaceNum; + + dbg_time("idVendor=%04x, idProduct=%04x, interfaceNum=%d\n", *idVendor, *idProduct, *interfaceNum); + + return fd; +} + +static int qtcp_read(int fd, void *pbuf, int size, int timeout_msec) { + static TLV tlv = {Q_USB2TCP_VERSION, 0}; + int cur = 0; + int len; + + if (tlv.length == 0) { + len = read(fd, &tlv, sizeof(tlv)); + if (len != sizeof(tlv)) { + dbg_time("%s read=%d, errno: %d (%s)\n", __func__, len, errno, strerror(errno)); + return 0; + } + + if (tlv.tag != Q_USB2TCP_VERSION) { + dbg_time("%s tlv->tag=0x%x\n", __func__, tlv.tag); + return 0; + } + } + + if (size > tlv.length) + size = tlv.length; + tlv.length -= size; + + while (cur < size) { + if (poll_wait(fd, POLLIN, timeout_msec)) + break; + + len = read(fd, (uint8_t *)pbuf+cur, size-cur); + if (len > 0) { + cur += len; + } + else { + dbg_time("%s read=%d, errno: %d (%s)\n", __func__, len, errno, strerror(errno)); + break; + } + } + + if (cur != size) { + dbg_time("%s cur=%d, size=%d\n", __func__, cur, size); + } + + return cur; +} + +static int qtcp_write(int fd, void*pbuf, int size, int timeout_msec) { + TLV tlv = {Q_USB2TCP_VERSION, size}; + int cur = 0; + int len; + + len = write(fd, &tlv, sizeof(tlv)); + if (len != sizeof(tlv)) { + dbg_time("%s write=%d, errno: %d (%s)\n", __func__, len, errno, strerror(errno)); + return 0; + } + + while (cur < size) { + if (poll_wait(fd, POLLOUT, timeout_msec)) + break; + + len = write(fd, (uint8_t *)pbuf+cur, size-cur); + if (len > 0) { + cur += len; + } + else { + dbg_time("%s write=%d, errno: %d (%s)\n", __func__, len, errno, strerror(errno)); + break; + } + } + + if (cur != size) { + dbg_time("%s cur=%d, size=%d\n", __func__, cur, size); + } + + return cur; +} + +struct usbfs_getdriver +{ + unsigned int interface; + char driver[255 + 1]; +}; + +struct usbfs_ioctl +{ + int ifno; /* interface 0..N ; negative numbers reserved */ + int ioctl_code; /* MUST encode size + direction of data so the + * macros in give correct values */ + void *data; /* param buffer (in, or out) */ +}; + +#define IOCTL_USBFS_DISCONNECT _IO('U', 22) +#define IOCTL_USBFS_CONNECT _IO('U', 23) + +int usbfs_is_kernel_driver_alive(int fd, int ifnum) +{ + struct usbfs_getdriver getdrv; + getdrv.interface = ifnum; + if (ioctl(fd, USBDEVFS_GETDRIVER, &getdrv) < 0) { + if (errno != ENODATA) + dbg_time("%s ioctl USBDEVFS_GETDRIVER failed, errno: %d (%s)\n", __func__, errno, strerror(errno)); + return 0; + } + dbg_time("%s find interface %d has match the driver %s\n", __func__, ifnum, getdrv.driver); + return 1; +} + +void usbfs_detach_kernel_driver(int fd, int ifnum) +{ + struct usbfs_ioctl operate; + operate.data = NULL; + operate.ifno = ifnum; + operate.ioctl_code = IOCTL_USBFS_DISCONNECT; + if (ioctl(fd, USBDEVFS_IOCTL, &operate) < 0) { + dbg_time("%s detach kernel driver failed\n", __func__); + } else { + dbg_time("%s detach kernel driver success\n", __func__); + } +} + +#define KVERSION(j,n,p) ((j)*1000000 + (n)*1000 + (p)) +static struct utsname utsname; /* for the kernel version */ +static int ql_get_kernel_version(void) +{ + int osmaj, osmin, ospatch; + int kernel_version; + + uname(&utsname); + osmaj = osmin = ospatch = 0; + sscanf(utsname.release, "%d.%d.%d", &osmaj, &osmin, &ospatch); + kernel_version = KVERSION(osmaj, osmin, ospatch); + + return kernel_version; +} + +static int detect_xhci_usb_zero_packet_bug_not_fix(const char *module_sys_path) { + char buf[256]; + int tmp; + char *driver; + + tmp = snprintf(buf, sizeof(buf), "/sys/bus/usb/devices/usb%c/../driver", module_sys_path[strlen("/sys/bus/usb/devices/")]); + driver = buf + (++tmp); + *driver = '\0'; + + tmp = readlink(buf, driver, sizeof(buf) - tmp); + dbg_time("tmp=%s, driver=%s\n", buf, driver); + if (tmp <= 0) + return 0; + + if (!strstr(driver, "xhci")) + return 0; + + tmp = ql_get_kernel_version(); + if (tmp >= KVERSION(4,3,0)) + return 0; + + dbg_time("WARNNING ON File:%s Function:%s Line:%d\n", __FILE__, __func__, __LINE__); + dbg_time("The module attach to XHCI controller, but your kernel verison less than V4.3.0\n"); + dbg_time("Please make sure your kernel had apply patch 'usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers'\n"); + dbg_time("https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/drivers/usb/host/xhci-ring.c?id=4758dcd19a7d9ba9610b38fecb93f65f56f86346\n"); + sleep(2); //sleep 2 seconds, make sure FAE/customers can notice this warnning. + + return 1; +} + +void *qusb_noblock_open(const char *module_sys_path, int *idVendor, int *idProduct, int *interfaceNum) { + struct termios ios; + int retval; + int fd = -1; + struct quectel_usb_device *udev = &quectel_9x07; + + *idVendor = *idProduct = *interfaceNum = 0; + tcp_socket_fd = -1; + + if (module_sys_path && module_sys_path[0] == '/') { + char port_name[64]; + + memset(udev, 0, sizeof(struct quectel_usb_device)); + quectel_get_usb_device_info(module_sys_path, udev); + if (udev->desc <= 0) + return NULL; + quectel_get_ttyport_by_syspath(module_sys_path, port_name, sizeof(port_name)); + detect_xhci_usb_zero_packet_bug_not_fix(module_sys_path); + + *idVendor = udev->idVendor; + *idProduct = udev->idProduct; + *interfaceNum = udev->bNumInterfaces; + + if (port_name[0] == '\0' || (port_name[0] != '\0' && access(port_name, R_OK)) || (udev->idVendor == 0x05c6 && udev->idProduct == 0x9008)) { + int bInterfaceNumber = 0; + + if (usbfs_is_kernel_driver_alive(udev->desc, bInterfaceNumber)) { + usbfs_detach_kernel_driver(udev->desc, bInterfaceNumber); + } + retval = ioctl(udev->desc, USBDEVFS_CLAIMINTERFACE, &bInterfaceNumber); + if(retval != 0) { + dbg_time("Fail to claim interface %d, errno: %d (%s)\n", bInterfaceNumber, errno, strerror(errno)); + if (udev->idVendor == 0x05c6) { + int n; + struct { + char infname[255 * 2]; + char driver[255 * 2]; + } *pl; + const char *driver = NULL; + + pl = (typeof(pl)) malloc(sizeof(*pl)); + + snprintf(pl->infname, sizeof(pl->infname), "%.255s:1.%d/driver", module_sys_path, usb_dm_interface); + n = readlink(pl->infname, pl->driver, sizeof(pl->driver)); + if (n > 0) { + pl->driver[n] = '\0'; + while (pl->driver[n] != '/') + n--; + driver = (&pl->driver[n+1]); + } + + dbg_time("Error: when module in 'Emergency download mode', should not register any usb driver\n"); + if (driver) + dbg_time("Error: it register to usb driver ' %s ' now, should delete 05c6&9008 from the source file of this driver\n", driver); + if (driver && !strcmp(driver, "qcserial")) + dbg_time("Delete 05c6&9008 from 'drivers/usb/serial/qcserial.c' or disable qcserial from kernel config\n"); + qusb_noblock_close(udev); + free(pl); + } + return NULL; + } + + udev->ttyfd = -1; + return udev; + } + else if (!access(port_name, R_OK)) { + dbg_time("%s port_name = %s\n", __func__, port_name); + + fd = open (port_name, O_RDWR | O_SYNC); + + if (fd <= 0) { + dbg_time("Device %s could not be open: Linux System Errno: %s", port_name, strerror (errno)); + return NULL; + } + + retval = tcgetattr (fd, &ios); + if (-1 == retval) { + dbg_time("ermio settings could not be fetched Linux System Error:%s", strerror (errno)); + return NULL; + } + + cfmakeraw (&ios); + cfsetispeed(&ios, B115200); + cfsetospeed(&ios, B115200); + + retval = tcsetattr (fd, TCSANOW, &ios); + if (-1 == retval) { + dbg_time("Device could not be configured: Linux System Errno: %s", strerror (errno)); + } + udev->ttyfd = fd; + fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK); + + return udev; + } + else { + dbg_time("fail to access %s errno: %d (%s)\n", port_name, errno, strerror(errno)); + } + } + else { + fd = qtcp_connect(module_sys_path, idVendor, idProduct, interfaceNum); + if (fd > 0) { + tcp_socket_fd = fd; + fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK); + return &tcp_socket_fd; + } + } + + return NULL; +} + +int qusb_noblock_close(void *handle) { + struct quectel_usb_device *udev = &quectel_9x07; + + if (handle == &tcp_socket_fd) { + close(tcp_socket_fd); + tcp_socket_fd = -1; + } if (handle == udev && udev->ttyfd > 0) { + close(udev->ttyfd); + close(udev->desc); + } + else if (handle == udev && udev->desc > 0) { + int bInterfaceNumber = 0; + ioctl(udev->desc, USBDEVFS_RELEASEINTERFACE, &bInterfaceNumber); + close(udev->desc); + } + else if (handle == &edl_pcie_mhifd && edl_pcie_mhifd > 0) { + close(edl_pcie_mhifd); edl_pcie_mhifd = -1; + } + memset(udev, 0, sizeof(*udev)); + + return 0; +} + +int qusb_use_usbfs_interface(const void *handle) { + struct quectel_usb_device *udev = &quectel_9x07; + + return (handle == udev && udev->ttyfd <= 0 && udev->desc > 0); +} + +int qusb_noblock_read(const void *handle, void *pbuf, int max_size, int min_size, int timeout_msec) { + struct quectel_usb_device *udev = &quectel_9x07; + int cur = 0; + int poll_ret = 0; + + if (min_size == 0) + min_size = 1; + if (timeout_msec == 0) + timeout_msec = 3000; + +#if 0 //depend on your worst net speed + if (handle == &tcp_socket_fd) { + if (timeout_msec > 1000) //before sahala&firebose, we allow read timeout occurs + timeout_msec = 120*1000; + } +#endif + + while (cur < min_size) { + int len = 0; + + if (handle == &tcp_socket_fd) { + if ((poll_ret = poll_wait(tcp_socket_fd, POLLIN, timeout_msec))) + break; + len = qtcp_read(tcp_socket_fd, (uint8_t *)pbuf+cur, max_size-cur, timeout_msec); + } + else if (handle == udev && udev->ttyfd > 0) { + if ((poll_ret = poll_wait(udev->ttyfd, POLLIN, timeout_msec))) + break; + len = read(udev->ttyfd, (uint8_t *)pbuf+cur, max_size-cur); + } + else if (handle == udev && udev->desc > 0) { + len = usbfs_bulk_read(udev, (uint8_t *)pbuf+cur, max_size-cur, timeout_msec); + } + else if (handle == &edl_pcie_mhifd && edl_pcie_mhifd > 0) { + if ((poll_ret = poll_wait(edl_pcie_mhifd, POLLIN, timeout_msec))) + break; + len = read(edl_pcie_mhifd, (uint8_t *)pbuf+cur, max_size-cur); + } + else { + break; + } + + if (len > 0) { + cur += len; + } else { + dbg_time("%s read=%d, errno: %d (%s)\n", __func__, len, errno, strerror(errno)); + break; + } + } + + if (poll_ret == EIO) + return -1; + else if (poll_ret == ETIMEDOUT) + return cur; + + if (cur < min_size) { + dbg_time("%s cur=%d, min_size=%d\n", __func__, cur, min_size); + } + + return cur; +} + +int qusb_noblock_write(const void *handle, void *pbuf, int max_size, int min_size, int timeout_msec, int need_zlp) { + struct quectel_usb_device *udev = &quectel_9x07; + int cur = 0; + + if (min_size == 0) + min_size = 1; + if (timeout_msec == 0) + timeout_msec = 3000; + +#if 0 //depend on your worst net speed + if (handle == &tcp_socket_fd) { + timeout_msec = 120*1000; + } +#endif + + while (cur < min_size) { + int len = 0; + + if (handle == &tcp_socket_fd) { + if (poll_wait(tcp_socket_fd, POLLOUT, timeout_msec)) + break; + len = qtcp_write(tcp_socket_fd, (uint8_t *)pbuf+cur, max_size-cur, timeout_msec); + } + else if (handle == udev && udev->ttyfd > 0) { + if (poll_wait(udev->ttyfd, POLLOUT, timeout_msec)) + break; + len = write(udev->ttyfd, (uint8_t *)pbuf+cur, max_size-cur); + } else if (handle == udev && udev->desc > 0) { + len = usbfs_bulk_write(udev, (uint8_t *)pbuf+cur, max_size-cur, timeout_msec, need_zlp); + } + else if (handle == &edl_pcie_mhifd && edl_pcie_mhifd > 0) { + if (poll_wait(edl_pcie_mhifd, POLLOUT, timeout_msec)) + break; + len = write(edl_pcie_mhifd, (uint8_t *)pbuf+cur, max_size-cur); + } + else { + break; + } + + if (len > 0) { + cur += len; + } else { + dbg_time("%s write=%d, errno: %d (%s)\n", __func__, len, errno, strerror(errno)); + break; + } + } + + if (cur < min_size) { + dbg_time("%s cur=%d, min_size=%d\n", __func__, cur, min_size); + } + + return cur; +} + +int qfile_find_xmlfile(const char *dir, const char *prefix, char** xmlfile) { + DIR *pdir; + struct dirent* ent = NULL; + pdir = opendir(dir); + + dbg_time("dir=%s\n", dir); + if(pdir) + { + while((ent = readdir(pdir)) != NULL) + { + if(!strncmp(ent->d_name, prefix, strlen(prefix)) && strncmp(ent->d_name, "rawprogram0.xml.bak", 15)) + { + dbg_time("d_name=%s\n", ent->d_name); + *xmlfile = strdup(ent->d_name); + closedir(pdir); + return 0; + } + } + + } + + closedir(pdir); + return 1; +} + +const char * firehose_get_time(void) { + static char time_buf[50]; + struct timeval tv; + static int s_start_msec = -1; + int now_msec, cost_msec; + + gettimeofday (&tv, NULL); + now_msec = tv.tv_sec * 1000; + now_msec += (tv.tv_usec + 500) / 1000; + + if (s_start_msec == -1) { + s_start_msec = now_msec; + } + + cost_msec = now_msec - s_start_msec; + + sprintf(time_buf, "[%03d.%03d]", cost_msec/1000, cost_msec%1000); + return time_buf; +} + +// void dbg_time (const char *fmt, ...) { +// va_list args; +// va_start(args, fmt); +// static char line[2048]; +// snprintf(line, sizeof(line), "%s ", firehose_get_time()); +// vsnprintf(line + strlen(line), sizeof(line) - strlen(line), fmt, args); +// fprintf(stdout, "%s", line); +// fflush(stdout); +// } + +int qpcie_open(const char *firehose_dir) { + int bhifd, edlfd, diagfd; + long ret; + FILE *fp; + BHI_INFO_TYPE *bhi_info = malloc(sizeof(BHI_INFO_TYPE)); + char prog_firehose_sdx24[256+32]; + size_t filesize; + void *filebuf; + + snprintf(prog_firehose_sdx24, sizeof(prog_firehose_sdx24), "%.255s/prog_firehose_sdx24.mbn", firehose_dir); + if (access(prog_firehose_sdx24, R_OK)) + snprintf(prog_firehose_sdx24, sizeof(prog_firehose_sdx24), "%.255s/prog_firehose_sdx55.mbn", firehose_dir); + + fp = fopen(prog_firehose_sdx24, "rb"); + if (fp ==NULL) { + dbg_time("fail to fopen %s, errno: %d (%s)\n", prog_firehose_sdx24, errno, strerror(errno)); + error_return(); + } + + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + filebuf = malloc(sizeof(filesize)+filesize); + memcpy(filebuf, &filesize, sizeof(filesize)); + if (fread((uint8_t *)filebuf+sizeof(filesize), 1, filesize, fp) == (size_t)0) { }; + fclose(fp); + + diagfd = open("/dev/mhi_DIAG", O_RDWR | O_NOCTTY); + if (diagfd > 0) + { + int edl_retry = 30; //SDX55 require long time by now 20190412 + void *usb_handle = &edl_pcie_mhifd; + edl_pcie_mhifd = diagfd; + + while (access("/dev/mhi_DIAG", R_OK) == 0 && edl_retry-- > 0) { + dbg_time("switch_to_edl_mode\n"); + switch_to_edl_mode(usb_handle); + sleep(1); + } + + close(diagfd); + edl_pcie_mhifd = -1; + } + + bhifd = open("/dev/mhi_BHI", O_RDWR | O_NOCTTY); + if (bhifd <= 0) { + dbg_time("fail to open %s, errno: %d (%s)\n", "/dev/mhi_BHI", errno, strerror(errno)); + error_return(); + } + + ret = ioctl(bhifd, IOCTL_BHI_GETDEVINFO, bhi_info); + if (ret) { + dbg_time("fail to ioctl IOCTL_BHI_GETDEVINFO, errno: %d (%s)\n", errno, strerror(errno)); + error_return(); + } + + dbg_time("bhi_ee = %d\n", bhi_info->bhi_ee); + if (bhi_info->bhi_ee != MHI_EE_EDL) { + dbg_time("bhi_ee is not MHI_EE_EDL\n"); + close(bhifd); + free(filebuf); + error_return(); + } + free(bhi_info); + + ret = ioctl(bhifd, IOCTL_BHI_WRITEIMAGE, filebuf); + if (ret) { + dbg_time("fail to ioctl IOCTL_BHI_GETDEVINFO, errno: %d (%s)\n", errno, strerror(errno)); + error_return(); + } + + close(bhifd); + free(filebuf); + + sleep(1); + edlfd = open("/dev/mhi_EDL", O_RDWR | O_NOCTTY); + if (edlfd <= 0) { + dbg_time("fail to access %s, errno: %d (%s)\n", "/dev/mhi_EDL", errno, strerror(errno)); + error_return(); + } + + edl_pcie_mhifd = edlfd; + + return 0; +} + +int usbmon_fd = -1; +int usbmon_logfile_fd = -1; + +void *catch_log(void *arg) +{ + int nreads = 0; + char tbuff[256]; + size_t off = strlen("[999.999] "); + + tbuff[off - 1] = ' '; + while(1) { + nreads = read(usbmon_fd, tbuff + off, sizeof(tbuff) - off); + if (nreads == -1 && errno == EINTR) + continue; + if (nreads <= 0) + break; + + tbuff[off + nreads] = '\0'; + memcpy(tbuff, firehose_get_time(), off - 1); + + if (write(usbmon_logfile_fd, tbuff, strlen(tbuff)) == -1) { }; + } + + return NULL; +} + +int ql_capture_usbmon_log(const char* usbmon_logfile) +{ + const char *usbmon_path = "/sys/kernel/debug/usb/usbmon/0u"; + pthread_t pt; + pthread_attr_t attr; + + if (access("/sys/kernel/debug/usb", F_OK)) { + dbg_time("debugfs is not mount, please execute \"mount -t debugfs none_debugs /sys/kernel/debug\"\n"); + return -1; + } + if (access("/sys/kernel/debug/usb/usbmon", F_OK)) { + dbg_time("usbmon is not load, please execute \"modprobe usbmon\" or \"insmod usbmon.ko\"\n"); + return -1; + } + + usbmon_fd = open(usbmon_path, O_RDONLY); + if (usbmon_fd < 0) { + dbg_time("open %s error(%d) (%s)\n", usbmon_path, errno, strerror(errno)); + return -1; + } + + usbmon_logfile_fd = open(usbmon_logfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (usbmon_logfile_fd < 0) { + dbg_time("open %s error(%d) (%s)\n", usbmon_logfile, errno, strerror(errno)); + close(usbmon_fd); + return -1; + } + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&pt, &attr, catch_log, NULL); + + return 0; +} + +void ql_stop_usbmon_log() +{ + if (usbmon_logfile_fd > 0) + close(usbmon_logfile_fd); + if (usbmon_fd > 0) + close(usbmon_fd); +} diff --git a/rooter/0optionalapps/qfirehose/src/usb_linux.h b/rooter/0optionalapps/qfirehose/src/usb_linux.h new file mode 100644 index 0000000..2f625f7 --- /dev/null +++ b/rooter/0optionalapps/qfirehose/src/usb_linux.h @@ -0,0 +1,142 @@ +#ifndef __QFIREHOSE_USB_LINUX_H__ +#define __QFIREHOSE_USB_LINUX_H__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PATH 256 +#define MIN(a,b) ((a) < (b)? (a) : (b)) + +extern const char *g_part_upgrade; + +typedef struct module_sys_info { +/* +MAJOR=189 +MINOR=1 +DEVNAME=bus/usb/001/002 +DEVTYPE=usb_device +DRIVER=usb +PRODUCT=2c7c/415/318 +TYPE=239/2/1 +BUSNUM=001 +*/ + //char sys_path[MAX_PATH]; + int MAJOR; + int MINOR; + char DEVNAME[64]; + char DEVTYPE[64]; + char PRODUCT[64]; +}MODULE_SYS_INFO; + +void * qusb_noblock_open(const char *module_sys_path, int *idVendor, int *idProduct, int *interfaceNum); +int qusb_noblock_close(void *handle); +int qusb_noblock_write(const void *handle, void *pbuf, int max_size, int min_size, int timeout_msec, int need_zlp); +int qusb_noblock_read(const void *handle, void *pbuf, int max_size, int min_size, int timeout_msec); +int qfile_find_xmlfile(const char *dir, const char *prefix, char** xmlfile); +#define errno_nodev() (errno == ENOENT || errno == ENODEV) +// void dbg_time (const char *fmt, ...); +const char * firehose_get_time(void); +extern FILE *loghandler; +#ifdef FH_DEBUG +#define dbg_time(fmt, args...) \ + do \ + { \ + fprintf(stdout, "[%15s-%04d]%s: " fmt, __FILE__, __LINE__, firehose_get_time(), ##args); \ + fflush(stdout); \ + if (loghandler) \ + fprintf(loghandler, "[%15s-%04d]%s: " fmt, __FILE__, __LINE__, firehose_get_time(), ##args); \ + } while (0); +#else +#define dbg_time(fmt, args...) \ + do \ + { \ + fprintf(stdout, "%s: " fmt, firehose_get_time(), ##args); \ + fflush(stdout); \ + if (loghandler) \ + fprintf(loghandler, "%s: " fmt, firehose_get_time(), ##args); \ + } while (0); +#endif +double get_now(); +void get_duration(double start); +int update_transfer_bytes(long long bytes_cur); +void set_transfer_allbytes(long long bytes); +int auto_find_quectel_modules(char *module_sys_path, unsigned size); +void quectel_get_syspath_name_by_ttyport(const char *module_port_name, char *module_sys_path, unsigned size); +void quectel_get_ttyport_by_syspath(const char *module_sys_path, char *module_port_name, unsigned size); +#define error_return() do {dbg_time("%s %s %d fail\n", __FILE__, __func__, __LINE__); return __LINE__; } while(0) + +extern int edl_pcie_mhifd; + +#define IOCTL_BHI_GETDEVINFO 0x8BE0 + 1 +#define IOCTL_BHI_WRITEIMAGE 0x8BE0 + 2 + +typedef unsigned int ULONG; + +typedef struct _bhi_info_type +{ + ULONG bhi_ver_minor; + ULONG bhi_ver_major; + ULONG bhi_image_address_low; + ULONG bhi_image_address_high; + ULONG bhi_image_size; + ULONG bhi_rsvd1; + ULONG bhi_imgtxdb; + ULONG bhi_rsvd2; + ULONG bhi_msivec; + ULONG bhi_rsvd3; + ULONG bhi_ee; + ULONG bhi_status; + ULONG bhi_errorcode; + ULONG bhi_errdbg1; + ULONG bhi_errdbg2; + ULONG bhi_errdbg3; + ULONG bhi_sernum; + ULONG bhi_sblantirollbackver; + ULONG bhi_numsegs; + ULONG bhi_msmhwid[6]; + ULONG bhi_oempkhash[48]; + ULONG bhi_rsvd5; +}BHI_INFO_TYPE, *PBHI_INFO_TYPE; + +enum MHI_EE { + MHI_EE_PBL = 0x0, /* Primary Boot Loader */ + MHI_EE_SBL = 0x1, /* Secondary Boot Loader */ + MHI_EE_AMSS = 0x2, /* AMSS Firmware */ + MHI_EE_RDDM = 0x3, /* WIFI Ram Dump Debug Module */ + MHI_EE_WFW = 0x4, /* WIFI (WLAN) Firmware */ + MHI_EE_PT = 0x5, /* PassThrough, Non PCIe BOOT (PCIe is BIOS locked, not used for boot */ + MHI_EE_EDL = 0x6, /* PCIe enabled in PBL for emergency download (Non PCIe BOOT) */ + MHI_EE_FP = 0x7, /* FlashProg, Flash Programmer Environment */ + MHI_EE_BHIE = MHI_EE_FP, + MHI_EE_UEFI = 0x8, /* UEFI */ + + MHI_EE_DISABLE_TRANSITION = 0x9, + MHI_EE_MAX +}; +int qpcie_open(const char *firehose_dir); + +#define Q_USB2TCP_VERSION 0x12345678 +typedef struct { + int tag; + int length; + int value[]; +} TLV; + +typedef struct { + int tag; + int length; + int idVendor; + int idProduct; + int interfaceNum; +} TLV_USB; +#endif diff --git a/rooter/0optionalapps/qlog/Makefile b/rooter/0optionalapps/qlog/Makefile new file mode 100644 index 0000000..cef8271 --- /dev/null +++ b/rooter/0optionalapps/qlog/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (C) 2011-2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=qlog +PKG_RELEASE:=1 + +PKG_FLAGS:=nonshared + +include $(INCLUDE_DIR)/package.mk + +define Package/qlog + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + TITLE:=Quectel Qlog + MAINTAINER:=Dairyman +endef + +define Package/qlog/description + Quectel Qlog +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" \ + CFLAGS="$(TARGET_CFLAGS) -Wall" +endef + +define Package/qlog/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/QLog $(1)/usr/bin/QLog + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,qlog)) diff --git a/rooter/0optionalapps/qlog/files/usr/lib/conf/T1.LinuxData-OTA-DataService-AP_V01.cfg b/rooter/0optionalapps/qlog/files/usr/lib/conf/T1.LinuxData-OTA-DataService-AP_V01.cfg new file mode 100644 index 0000000000000000000000000000000000000000..f66248605d6bcf956dd5140a7b95d7359a1d5104 GIT binary patch literal 2012 zcmb1@v94pN_)zC<#Ky48x2|TgXPwMctvVhNtGeW;3+uf385nja)Om9pvutE-J=WdMT`M<5$$1qjFh@y$*UpOpb5 zEf2)!mV@~04D3+;`!68A7K0X)4|F|{ufw1N<+p`^_>K&YP(GU}h#$ca0p%-(g7{Gk zQBXbu8;IW_yh0daAIQ#u#NMqS_pB0L1$EESKXt`GCxO7NMlh2Z$Yca!V_-CW05KR2 z06D-IWH=z4zyOj3fdgO}2pdicz*!&$8w!s&&hP*K|J$P|l|bR);D9Z507_zW6%IW_ z3I7143wCEQc*uZ~k^!-{G{^+OHG&dcD=$%&GB7kSK$9$X^$sNX6E#k-n>Xx48}R#x zr0}z9fyW^zF<5isHycS7ZyX}28)ae-0hVu1;6V=x^>=sz6qF@-46vI+4^fc)ECw?^ q!W|6C>Q4yR%<-bKE`dQPt1f|Yc6D77P<0+2FA^|}7Samer0M{1B6I=( literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/qlog/files/usr/lib/conf/T2.RegServ-CotextAct_V01.cfg b/rooter/0optionalapps/qlog/files/usr/lib/conf/T2.RegServ-CotextAct_V01.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8645a8a5d3c2e76fe9e28ae30754b735ac060f44 GIT binary patch literal 2260 zcmds2T}TvB6h5=R+Lj}$h{f8jgdvf#Xd!8^NiWIPgM}zbWD14#pkhRs%@`8)ScLUZ zSP}FiJ@h0}Q4(Yjlob`#gR4m?S~(H1h3lTqnVs1kCs*txr~{XCzVmm_d^7h>j;Bn5 z!-^Cva=`6vQu~<-$Q*bQzCdk-k{ zZ=5mAJ&X%Y{#AvX-|rf9#qtnkkPS6xu#J7pc25)cxg_=yN#+;|dT#-c20(J?a}4{r z?qtUGjNj|bef|axp5S?UGkUdo9!3~@@>b_*^ASNZaT1`#nrA|dd)3CTv2P@o>s?irMd%pZBR}#%u{eSl!dY~2NI~n9PBx5^2Ff|a zK*Hrnm;eJZz(GX-7? zNcPqDapL&&`WHJyhi7}dkk7a~4S?C#rTGE|BHur4CW#lL)FCAjUD>R~Y_I?P%0{;wS*LUo)SL5Uq MR&+~s;NCC&0_5W$wg3PC literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/qlog/files/usr/lib/conf/T3.SimpleData-(TCPUDP)_V01.cfg b/rooter/0optionalapps/qlog/files/usr/lib/conf/T3.SimpleData-(TCPUDP)_V01.cfg new file mode 100644 index 0000000000000000000000000000000000000000..6289c58433222df1cc878ef6fd4c05bf5b949289 GIT binary patch literal 2144 zcmds2TSydP6h5<8Wo<`RA1qef7eOLwyJ2auN-xP2VG%xrWCaDiq}YSke>NoSF$n9S z=t2*r^w3Kp79~Okfo(*A^x!H|l6D!0*uZs9=giLRjFTHd5Y$=z`ObaLoc}-nmWOKv zbZA1^;)BusqUTbB2oJ0mMWr?3#JgKUkpUjI2&E9<_^?n403LrNkl^Gup?Cnw8wg~0 z^PD`(K)ODtqsx1ha065=2qm-=7P|>{!67d}H7v~%)WVUy1lvJ*MNk8MjRa7z_Oj@0 z_JU4l>xrjVFjdehy~nZ_*v#^aJ1omU73y-=eU>8-G33T!mS6f``?GeAv9IRdW_FnJ zPZo!2O|u-XtgHkm<6a=DDq)NkBiDp(t9JJ38045hm0U$O za$q0(x;Q7=NyYT`oX%1LpeDgM9X(BoPaIR9MPREugP6o+3~VNohVIEe_5s*o`~ZTW zT|tcLTKy5USb#Ayyhk-Nox(GVya}t*60S%=PW%y`IG4VHIsl@ULSuVf+N~FEssEh& zPDcZ1#XDU_vN}fn!Hh;nj4O=$ponFITn*K^Uh*VG^M0@yVPHIbFc--47NREdhM3fP z4P)t4oA)RyxHgkCY~p#$l08C8QA@uj5Ir;Vh~+f3#im;xY<1`*$;#|7{S%_S8+!lR zB-q21JNierjY0MZ>fb!35-Rm?PS*QpdgViBeGVT3i`7&5~{8B+9 zy;}dV+PC1(enMJ{SP_taxNJ@U=6PPB{O<%jVw6~`m!J*VIN{?v@5+NQ$$7h5Rw%X)I*9rXsdTNB<#H` zs3@zK@(&0xF%c>VV*4<#9$H08(mnFcQ$R5#iu~~!$szq^GgE;p7mQWRd2W>)K190@dP>TS@J`qT8{JT&+02R#y z3cP+w%yN)!+%wSSy+&9ARr5j(Zi9t5!FD*{C8&qR8G=SQw2Pn))RzPe(6^5Oiq>5g zy{%p_?yMhOrFW&*e!u*KhGG zZ0&7j!jwE^5|Tl-hyBC;+{BlzvOVG-C0jEm;ow)N*gvQYQjIvlVVUjQ$`IMs;3(yE zBn45XMrh8X#hHJh^lqumx8nW=s^>YMq0%8UpGQXFLXk)WAjIoN)HK26zs*imQ|=+s{01Wp6|$0n6KShDyOe1%e4WUb>Wcd_;Rv37eH^#1t-}eg6~w6FH9i4b1sJD}52$6|rSbFvZ$M#L#AQPei8s-cpd+(fx&UfzkIwzE zjN3@ucK^BdgN_AIOLV);!D5WYhZWsCW(gk@vu%p2xjtV@zAd$@F4&4NF%jCI59BKs zq$2W$SkitSqnUJv_b@v+H%oMEp;Sz9M(AlO>9-`JXL=5?0uuQJRKGb)CpD_ytYXy9Vy%Y!7CJ?eTs@HARi3nkrpk8q zk2_g~b^IEp>s+Y*Snr#cb4$qRm5%7uFPDP^V4de>&i~H96F$%mZpl}l_xOwX|79)q zCT({%ko80XA+>>?(abb;oeh4Rl*6eRR}o?|oBlkypq2Eec26jQHS{oAqILi7&9)+b xjXavCc5ghN@LF;-k(Vwp;vGuSz4S1JX^EbF>d8HehGq~@lhzN2HVB>+KLG)M5y=1m literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/qlog/files/usr/lib/conf/T5.COMMON-T1T4_V01.cfg b/rooter/0optionalapps/qlog/files/usr/lib/conf/T5.COMMON-T1T4_V01.cfg new file mode 100644 index 0000000000000000000000000000000000000000..57d1346c1f017cebaf587a8e647a1cbe6f51d251 GIT binary patch literal 4226 zcmeHJe`u6-7=PaTZ8vw`%`xY0+{Vxyk#aU;=0=xNGC&vQ-pSR2LIRMXoBFB9I z$FC8S;Dz7ixC@}Ng;)T7{F*EmfYke;;12gY#2Y71Lus;a?Q0x&K9pI+T;^t7IV`f! zF@`>L0#dWX({P0SYhj7zZ@?-RnPGVs>~1qDIQiR4S^1mvhsA^%!JT=T z?Jhg7IVVp%+pYMR_1B#@NRLg_hOqCWxh(tMJM6XgL6f{jVENR4%Ad7IR0<{tE$|yL z>iynrocBv5 zDmGM1&T-%h>jo-LTj-|BH++nJtHRaceB8C-{A-Rhle6$|W1HpGYpU}$Q^lQa{rVM* zAzBlwDa4TE`$D_;c`fUC?-Lhkc+p~dF$ftc6>SYOXBoNW>=7qKzpI+_4A-8o&Fh5! z6l*h7!G8W|AWCt`!R+(;1=cr48%fW)*kvAXjlQCd&G!G~_;4xbJ`_DV3%U19$UEqB zn10$Lx>Qu4#{itAr>QC>PCcWXu7bM2C}I-tpnn;uRCIp3mu=|Y*M0!SpuUBC_3Kou zcbE^7;u0#EkrZwl=S$d{Zeu|RGFm{*mEb9%40)nQPK-wh5lUsfl5q;)EFP}oe~o{8^a;+`4B()Fq#`{r7-7N#MeW3iSnmO6y(3pmdTT?> z_LGHE{x1=JGUvz-_7EY{atou5cd;p*+U|auM~qG<63BuV+mM)`lGZ>)x>-*yQeW$>o@(YsS4qX*S*3{yi2)$c+;)K9mvpc2mf5>1`|=Wc5=sjX K%Iy%^EdL2@L%Z|< literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/qlog/files/usr/lib/conf/T6.FullMessage.SimpleLogPacket(AT)_V01.cfg b/rooter/0optionalapps/qlog/files/usr/lib/conf/T6.FullMessage.SimpleLogPacket(AT)_V01.cfg new file mode 100644 index 0000000000000000000000000000000000000000..19499f09c185247ea6f928c1d5eca898a1cdd7c0 GIT binary patch literal 4191 zcmeHJeMnPL6hAhnD>d7u=-9+$m?J7y7MV(}|B?|=LKz~AiXagaicr(HNlHZoffYrd z_FtLw@lQmFETRtzDuO_Yl*-UbOz8v3=yuNay}kMNo}11JsypsGpTBd?&b{xxn_(*u zpk_pHuZV*i8-)6nV!?KDv5=UOFYI`GPH-m!-1G?Uxd7X*32p;G_Yjg8*!4wl#{y&& zBT0s55709mVp=b7I!AvN=@M|f7u=>b@ZkWGLMYKASq&hWON7sX zr6OJ}KVc7jC%;_SsF5c)KE?1V{20sBtRWby#qTbq{9B3+)c=F4;O7>yh zN3^pdoR3-C#U#=_iSLP5$1sK7&TF}za5rJXpE2*G1!5}o2iGX^t$QeMdvXW9W0Fpy z(#B!PFf4#mv5sCR;Z7J|8bfgs{y&}E8zWz{KI1@yJ$v+mdOT)~$I~a;UUtS(ti$H> z=ICQZTMOac%~Vf^xkIey4nK_QQ;((s6rnwuSa=b=U4v_-cZA{w>(qGinXRc7 zpLE^`>d?aeE`93&t&u2(#TG7K z&lSQhv}M`kxF!7jb7i^^%<<*qvodQ_mh2NQ?rht)P@W22m}%c49zIj?hM8^?#)nycz&aX%sg4Dd+#!}rBZx4n=kNL_!BIp#{G?BC3^5P)Obc#Aqla4#3*L4njwd>y*6?`Ky$puNAfAPI^dN384@@n|{RBEbiXl(H6 zAxfpVHmP5@)JVJ@;f_o{9e!!MI?F1dk3){gPS6BzlmYrU4<;<06hn!l0&jjZ(h?39 zy>WiVLD%GsIU*>|Q(1@XA0F4H_C>#Ca{ZgQZ*p2zXrvETNY^nT z3f>%_3^bWO2+rVli>VnHtmg+KO&R*(`xO^P3e>q=hG=q!UzeQRFc+tp-U%-7&xeu| zHb+=Rm|fhGbr%sbJ_pPNM=@Z@6BqK(YLJ?{;MXjd`6gf3Rr^seO+4JT2AdmjS`NrX zM2%mBdyHnQk OzmmD03yw%5ln zgc%G=7Czzg;V0IVzPcti_oi)rTJ!`+#QfniF8ke!mL!>d9%`IEUHOIUGF%{JUjPV#Mt9LKjlca1y}dwI5vY z{lM{=BQXyF3UD91Bbu0?KkDXaA!5AhJjUfbdMvCNba5_PV(duu=n2Z$``dsE<`m2^b9MCqXXoYR$+_fu zZ+VoHF5_kh7%`qwMP(tP_TSLUk?-U!h?O4Q8g{|{Tz(tdC!6uV^?$Hk+sY|{zTaVp zoV>9|;#`LjwU?;;Q&@wQ!zb4_4?D1Zycei%Cj_Fq<&PAF%F`oiW^|RI=SO-%FnGC@ z#HBzaCd5180M1Ke5b*6`Aw)&?Y_hm!vLw2pq;@ktM17VnHrR3NPuMG)0e&mt$bi8)+}ispAf7EOB+YBaIhCy||JK1+?p>mC-yG^^FyxwP!YV zQZ)$+m5$}~-|6|IViXBwaanR!aKYDdi5Ueg9qZdSFO4aD+JaC&2?~ib3Gr$k5$8qs z@N!=og@01SO;;PQiEy!{(#U2>)!vvg&tGn=LFRt-{H-19jl$=}r5>Mx`E%9&l3X72 zUdwlK>hg>gf^TWQT?1)2|3;H2vJa@{TE-&Y6e~W`u7h0H;dA4=i0AnbK71@W`#kX! z;t8@Rk9wjFtn0V-^G)xgvvb)$hD~0UU;Tj1T@%I{h#$W^*HT*(Af@r%@Y@B+XxJ9T z9PNcS*yl(ton_fl&dS5wC}^C@h%Smm_beMJ^F3M}xu4eRl+Grtl?@MPz;Qgn?K3fT z@x{or`y$?NTzV{FwbHkH#XZrAD?UyWALAp_#Xg&9S`#vR)nvW z6nt3d0@@Sk%M=#Qc)+;i!aNJXzqs$>UtMO&tDb+Aygv<%)%1e qOeYVMMZbK-sW<6GbNLLrHtDzR;h9$sTFv{`PD3iKplGgltM)ggN57;1 literal 0 HcmV?d00001 diff --git a/rooter/0optionalapps/qlog/src/Makefile b/rooter/0optionalapps/qlog/src/Makefile new file mode 100644 index 0000000..b5b7daa --- /dev/null +++ b/rooter/0optionalapps/qlog/src/Makefile @@ -0,0 +1,8 @@ +SOURCES = main.c asr.c mdm.c tty2tcp.c sahara.c + +linux: clean + ${CC} $(SOURCES) $(CFLAGS) -Wall -o QLog -lpthread -ldl + +clean: + rm -rf QLog *.exe *.dSYM *.obj *.exp .*o *.lib *~ libs out + diff --git a/rooter/0optionalapps/qlog/src/asr.c b/rooter/0optionalapps/qlog/src/asr.c new file mode 100644 index 0000000..af54c56 --- /dev/null +++ b/rooter/0optionalapps/qlog/src/asr.c @@ -0,0 +1,87 @@ +#include "qlog.h" + +struct CSDLFileHeader +{ + uint32_t dwHeaderVersion;//0x0 + uint32_t dwDataFormat;//0x1 + uint32_t dwAPVersion; + uint32_t dwCPVersion; + uint32_t dwSequenceNum;//ÎļþÐòºÅ£¬´Ó0¿ªÊ¼µÝÔö + uint32_t dwTime;//Total seconds from 1970.1.1 0:0:0 + uint32_t dwCheckSum;//0x0 +}; + +int g_is_asr_chip = 0; + +ssize_t asr_send_cmd(int ttyfd, const unsigned char *buf, size_t size) { + ssize_t wc = 0; + + while (wc < size) { + uint32_t *cmd_data = (uint32_t *)(buf+wc); + unsigned cmd_len = qlog_le32(cmd_data[0]); + //unsigned i; + + if (cmd_len > (size - wc)) + break; + + //qlog_dbg("Send CMD to UE: "); + //for(i=0; i ../../devices/soc0/soc/2100000.aips-bus/2184200.usb/ci_hdrc.1/usb1/1-1/1-1:1.0/ttyUSB0/tty/ttyUSB0 + pchar = strstr(syspath, ":1.0/tty"); //MDM + if (pchar == NULL) { + pchar = strstr(syspath, ":1.2/tty"); //ASR + g_is_asr_chip = (pchar != NULL); + } + if (pchar == NULL) { + qlog_dbg("%s is not a usb-to-serial device?\n", ttyport); + return; + } + + *pchar = '\0'; + while (*pchar != '/') + pchar--; + + strcpy(sysport, pchar + 1); + + snprintf(syspath, sizeof(syspath), "/sys/bus/usb/devices/%s/idVendor", sysport); + fd = open(syspath, O_RDONLY); + if (fd <= 0) { + qlog_dbg("Fail to open %s, errno: %d (%s)\n", syspath, errno, strerror(errno)); + return; + } + read(fd, idVendor, 4); + close(fd); + + snprintf(syspath, sizeof(syspath), "/sys/bus/usb/devices/%s/idProduct", sysport); + fd = open(syspath, O_RDONLY); + if (fd <= 0) { + qlog_dbg("Fail to open %s, errno: %d (%s)\n", syspath, errno, strerror(errno)); + return; + } + read(fd, idProduct, 4); + close(fd); + + snprintf(syspath, sizeof(syspath), "/sys/bus/usb/devices/%s/bNumInterfaces", sysport); + fd = open(syspath, O_RDONLY); + if (fd <= 0) { + qlog_dbg("Fail to open %s, errno: %d (%s)\n", syspath, errno, strerror(errno)); + return; + } + read(fd, bNumInterfaces, 4); + close(fd); + + qlog_dbg("%s idVendor=%s, idProduct=%s, bNumInterfaces=%d\n", __func__, idVendor, idProduct, atoi(bNumInterfaces)); +} + +static unsigned long get_now_msec() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*1000 + tv.tv_usec / 1000; +} + +static size_t ql_tty_read(int fd, void *buf, size_t size) +{ + size_t rc; + + rc = read(fd,buf,size); + + if (rc > 0) { + static size_t total_read = 0; + static unsigned long now_msec = 0; + unsigned long n = get_now_msec(); + + if (now_msec == 0) + now_msec = get_now_msec(); + total_read += rc; + + if ((total_read >= (4*1024*1024)) || (n >= (now_msec + 5000))) { + qlog_dbg("recv: %zdM %zdK %zdB in %ld msec\n", total_read/(1024*1024), + total_read/1024%1024,total_read%1024, n-now_msec); + now_msec = n; + total_read = 0; + } + } + + return rc; +} + +ssize_t qlog_poll_write(int fd, const void *buf, size_t size, unsigned timeout_msec) { + ssize_t wc = 0; + ssize_t nbytes; + + nbytes = write(fd, buf+wc, size-wc); + + if (nbytes <= 0) { + if (errno != EAGAIN) { + qlog_dbg("Fail to write fd = %d, errno : %d (%s)\n", fd, errno, strerror(errno)); + goto out; + } + else { + nbytes = 0; + } + } + + wc += nbytes; + + while (wc < size) { + int ret; + struct pollfd pollfds[] = {{fd, POLLOUT, 0}}; + + ret = poll(pollfds, 1, timeout_msec); + + if (ret <= 0) { + qlog_dbg("Fail to poll fd = %d, errno : %d (%s)\n", fd, errno, strerror(errno)); + break; + } + + if (pollfds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { + qlog_dbg("Fail to poll fd = %d, revents = %04x\n", fd, pollfds[0].revents); + break; + } + + if (pollfds[0].revents & (POLLOUT)) { + nbytes = write(fd, buf+wc, size-wc); + + if (nbytes <= 0) { + qlog_dbg("Fail to write fd = %d, errno : %d (%s)\n", fd, errno, strerror(errno)); + break; + } + wc += nbytes; + } + } + +out: + if (wc != size) { + qlog_dbg("%s fd=%d, size=%zd, timeout=%d, wc=%zd\n", __func__, fd, size, timeout_msec, wc); + } + + return (wc); +} + +static int qlog_logfile_create(const char *logfile_dir, const char *logfile_suffix, unsigned logfile_seq) { + int logfd; + time_t ltime; + char shortname[32]; + char filename[255+1]; + struct tm *currtime; + + //delete old logfile + if (s_logfile_num && s_logfile_List[logfile_seq%s_logfile_num][0]) { + sprintf(filename, "%s/%s.%s", logfile_dir, s_logfile_List[logfile_seq%s_logfile_num], logfile_suffix); + if (access(filename, R_OK) == 0) { + remove(filename); + } + } + + time(<ime); + currtime = localtime(<ime); + snprintf(shortname, sizeof(shortname), "%04d%02d%02d_%02d%02d%02d_%04d", + (currtime->tm_year+1900), (currtime->tm_mon+1), currtime->tm_mday, + currtime->tm_hour, currtime->tm_min, currtime->tm_sec, logfile_seq); + sprintf(filename, "%s/%s.%s", logfile_dir, shortname, logfile_suffix); + + logfd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0444); + if (logfd <= 0) { + qlog_dbg("Fail to create new logfile! errno : %d (%s)\n", errno, strerror(errno)); + } + + qlog_dbg("%s %s logfd=%d\n", __func__, filename, logfd); + + if (s_logfile_num) { + strcpy(s_logfile_List[logfile_seq%s_logfile_num], shortname); + } + + return logfd; +} + +static size_t qlog_logfile_save(int logfd, const void *buf, size_t size) { + return qlog_poll_write(logfd, buf, size, 1000); +} + +static int qlog_logfile_close(int logfd) { + return close(logfd); +} + +static void* qlog_logfile_init_filter_thread(void* arg) { + void **thread_args = (void **)arg; + qlog_ops_t *qlog_ops = (qlog_ops_t *)thread_args[0]; + int *ttyfd = (int *)thread_args[1]; + const char *filter_cfg = ( const char *)thread_args[2]; + + if (qlog_ops->init_filter) + qlog_ops->init_filter(*ttyfd, filter_cfg); + + return NULL; +} + +static int qlog_handle(int ttyfd, const char *logfile_dir, size_t logfile_size, unsigned logfile_num, const char *filter_cfg) { + ssize_t savelog_size = 0; + void *rbuf; + const size_t rbuf_size = (16*1024); + static int logfd = -1; + unsigned logfile_seq = 0; + const char *logfile_suffix = g_is_asr_chip ? "sdl" : "qmdl"; + static qlog_ops_t qlog_ops; + pthread_t thread_id; + pthread_attr_t thread_attr; + const void *thread_args[3]; + + if (logfile_dir[0] == '9' && atoi(logfile_dir) >= 9000) { + filter_cfg = logfile_dir; + qlog_ops = tty2tcp_qlog_ops; + } + else { + qlog_ops = g_is_asr_chip ? asr_qlog_ops : mdm_qlog_ops; + if (access(logfile_dir, F_OK) && errno == ENOENT) + mkdir(logfile_dir, 0755); + } + + if (!qlog_ops.logfile_create) + qlog_ops.logfile_create = qlog_logfile_create; + if (!qlog_ops.logfile_save) + qlog_ops.logfile_save = qlog_logfile_save; + if (!qlog_ops.logfile_close) + qlog_ops.logfile_close = qlog_logfile_close; + + rbuf = malloc(rbuf_size); + if (rbuf == NULL) { + qlog_dbg("Fail to malloc rbuf_size=%zd, errno: %d (%s)\n", rbuf_size, errno, strerror(errno)); + return -1; + } + + thread_args[0] = &qlog_ops; + thread_args[1] = &ttyfd; + thread_args[2] = filter_cfg; + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + pthread_create(&thread_id, &thread_attr, qlog_logfile_init_filter_thread, (void*)thread_args); + + while(1) { + ssize_t rc, wc; + int ret; + struct pollfd pollfds[] = {{ttyfd, POLLIN, 0}}; + + ret = poll(pollfds, 1, -1); + + if (ret <= 0) { + qlog_dbg("poll(ttyfd) =%d, errno: %d (%s)\n", ret, errno, strerror(errno)); + break; + } + + if (pollfds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { + qlog_dbg("ttyfd revents = %04x\n", pollfds[0].revents); + break; + } + + if (pollfds[0].revents & (POLLIN)) { + rc = ql_tty_read(ttyfd, rbuf, rbuf_size); + + if(rc > 0) { + if (logfd == -1) { + logfd = qlog_ops.logfile_create(logfile_dir, logfile_suffix, logfile_seq); + if (logfd <= 0) { + break; + } + if (qlog_ops.logfile_init) + qlog_ops.logfile_init(logfd, logfile_seq); + logfile_seq++; + } + + wc = qlog_ops.logfile_save(logfd, rbuf, rc); + + if (wc != rc) { + qlog_dbg("savelog fail %zd/%zd, break\n", wc, rc); + break; + } + + savelog_size += wc; + + if (savelog_size >= logfile_size) { + savelog_size = 0; + qlog_ops.logfile_close(logfd); + logfd = -1; + } + } + else + { + qlog_dbg("ttyfd recv %zd Bytes. break\n", rc); + break; + } + } + } + + if (logfd > 0) + qlog_ops.logfile_close(logfd); + free(rbuf); + + return 0; +} + +static void ql_sigaction(int signal_num) { + qlog_dbg("recv signal %d\n", signal_num); +} + +static void qlog_usage(const char *self, const char *dev) { + qlog_dbg("Usage: %s -p -s -f filter_cfg -n -b \n", self); + qlog_dbg("Default: %s -p %s -s %s -n %d -b %d to save log to local disk\n", + self, dev, ".", LOGFILE_NUM, LOGFILE_SIZE_DEFAULT/1024/1024); + qlog_dbg(" -p ttyport to catch log, default is '/dev/ttyUSB0'\n"); + qlog_dbg(" -s where to save log, default is '.' \n"); + qlog_dbg(" if set as '9000', QLog will run as TCP Server Mode, and let 'QPST/QWinLog/CATStudio' to connect!\n"); + qlog_dbg(" -f filter cfg for catch log, can be found in directory 'conf'. if not set this arg, will use default filter conf\n"); + qlog_dbg(" and UC200T&EC200T do not need filter cfg.\n"); + qlog_dbg(" -n max num of log file to save, range is '0~512'. default is 0. 0 means no limit.\n"); + qlog_dbg(" or QLog will auto delete oldtest log file if exceed max num\n"); + qlog_dbg(" -m max size of single log file, unit is MBytes, range is '2~512', default is 128\n"); + + qlog_dbg("\nFor example: %s -p /dev/ttyUSB0 -w .\n", self); +} + +int main(int argc, char **argv) +{ + int opt; + char ttyname[32] = "/dev/ttyUSB0"; + int ttyfd = -1; + const char *logfile_dir = "./"; + const char *filter_cfg = NULL; + size_t logfile_size = LOGFILE_SIZE_DEFAULT; + unsigned logfile_num = LOGFILE_NUM; + char idVendor[5] = "0000"; + char idProduct[5] = "0000"; + char bNumInterfaces[5] = "0"; + + qlog_dbg("QLog Version: Quectel_QLog_Linux&Android_V1.3\n"); //when release, rename to V1.X + + optind = 1; //call by popen(), optind mayby is not 1 + while ( -1 != (opt = getopt(argc, argv, "d:p:s:w:n:m:b:f:c:h"))) { + switch (opt) { + case 'p': + if (optarg[0] == 't') //ttyUSB0 + snprintf(ttyname, sizeof(ttyname), "/dev/%s", optarg); + else if (optarg[0] == 'U') //USB0 + snprintf(ttyname, sizeof(ttyname), "/dev/tty%s", optarg); + else if (optarg[0] == '/') + snprintf(ttyname, sizeof(ttyname), "%s", optarg); + else { + qlog_dbg("unknow dev %s\n", optarg); + } + break; + case 's': + logfile_dir = optarg; + break; + case 'n': + logfile_num = atoi(optarg); + if (logfile_num < 0) + logfile_num = 0; + else if (logfile_num > LOGFILE_NUM) + logfile_num = LOGFILE_NUM; + s_logfile_num = logfile_num; + break; + case 'm': + logfile_size = atoi(optarg)*1024*1024; + if (logfile_size < LOGFILE_SIZE_MIN) + logfile_size = LOGFILE_SIZE_MIN; + else if (logfile_size > LOGFILE_SIZE_MAX) + logfile_size = LOGFILE_SIZE_MAX; + break; + case 'f': + filter_cfg = optarg; + break; + case 'b': + case 'c': //unused + break; + default: + qlog_usage(argv[0], ttyname); + return 0; + break; + } + } + + signal(SIGTERM, ql_sigaction); + signal(SIGHUP, ql_sigaction); + signal(SIGINT, ql_sigaction); + + ttyfd = open (ttyname, O_RDWR | O_NDELAY | O_NOCTTY); + + if (ttyfd <= 0) { + qlog_dbg("Fail to open %s, errno : %d (%s)\n", ttyname, errno, strerror(errno)); + return -1; + } + + qlog_dbg("open %s ttyfd = %d\n", ttyname, ttyfd); + + if ( ttyfd > 0 ) { + struct termios ios; + + memset(&ios, 0, sizeof(ios)); + tcgetattr( ttyfd, &ios ); + cfmakeraw(&ios); + cfsetispeed(&ios, B115200); + cfsetospeed(&ios, B115200); + tcsetattr( ttyfd, TCSANOW, &ios ); + } + + if (strncmp(ttyname, "/dev/mhi", strlen("/dev/mhi"))) { + qlog_get_vidpid_by_ttyport(ttyname, idVendor, idProduct, bNumInterfaces); + } + else { + if (!strcmp(ttyname, "/dev/mhi_DIAG")) { + strcpy(idVendor, "2c7c"); + strcpy(bNumInterfaces, "5"); //log mode + } + else if (!strcmp(ttyname, "/dev/mhi_SAHARA")) { + strcpy(idVendor, "2c7c"); + strcpy(bNumInterfaces, "1"); //dump mode + } + } + + qlog_dbg("Press CTRL+C to stop catch log.\n"); + + if (g_is_asr_chip == 0 && atoi(bNumInterfaces) == 1) { + if (access(logfile_dir, F_OK) && errno == ENOENT) + mkdir(logfile_dir, 0755); + sahara_catch_dump(ttyfd, logfile_dir, 1); + } + else if (atoi(bNumInterfaces) > 1) { + qlog_handle(ttyfd, logfile_dir, logfile_size, logfile_num, filter_cfg); + } + else { + qlog_dbg("unknow state! quit!\n"); + } + + close(ttyfd); + + return 0; +} diff --git a/rooter/0optionalapps/qlog/src/mdm.c b/rooter/0optionalapps/qlog/src/mdm.c new file mode 100644 index 0000000..42d1adf --- /dev/null +++ b/rooter/0optionalapps/qlog/src/mdm.c @@ -0,0 +1,203 @@ +#include "qlog.h" + +static unsigned char qlog_mdm_default_cfg[] = { +0x1d,0x1c,0x3b,0x7e,0x00,0x78,0xf0,0x7e,0x4b,0x32,0x06,0x00,0xba,0x4d,0x7e,0x7c,0x93,0x49,0x7e,0x1c,0x95,0x2a,0x7e,0x0c,0x14,0x3a,0x7e,0x63,0xe5,0xa1,0x7e,0x4b, +0x0f,0x00,0x00,0xbb,0x60,0x7e,0x4b,0x09,0x00,0x00,0x62,0xb6,0x7e,0x4b,0x08,0x00,0x00,0xbe,0xec,0x7e,0x4b,0x08,0x01,0x00,0x66,0xf5,0x7e,0x4b,0x04,0x00,0x00,0x1d, +0x49,0x7e,0x4b,0x04,0x0f,0x00,0xd5,0xca,0x7e,0x4b,0x0f,0x18,0x00,0x01,0x9e,0xa9,0x7e,0x4b,0x0f,0x18,0x00,0x02,0x05,0x9b,0x7e,0x4b,0x0f,0x2c,0x00,0x28,0xea,0x7e, +0x4b,0x12,0x39,0x00,0xeb,0x7b,0x7e,0x4b,0x12,0x3c,0x00,0x53,0x05,0x7e,0x4b,0x12,0x37,0x00,0xfb,0xe1,0x7e,0x4b,0x12,0x3b,0x00,0x5b,0x48,0x7e,0x4b,0x12,0x35,0x00, +0x4b,0xd2,0x7e,0x4b,0x12,0x3a,0x00,0x83,0x51,0x7e,0x4b,0x12,0x00,0x08,0x19,0x96,0x7e,0x7d,0x5d,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x41,0x7e,0x7d,0x5d,0x04, +0x00,0x00,0x02,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x4c,0x06,0x7e,0x7d,0x5d,0x04,0x05,0x00,0x05,0x00,0x00,0x00,0x1f,0x00, +0x00,0x00,0xce,0xa7,0x7e,0x7d,0x5d,0x04,0x07,0x00,0x08,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0xd0,0x71,0x7e,0x7d,0x5d,0x04,0x0b,0x00,0x0c,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x7c,0x68,0x7e,0x7d,0x5d,0x04,0x0e,0x00,0x12,0x00,0x00,0x00,0xff,0x01,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0xb5,0x3a,0x7e,0x7d,0x5d,0x04,0x14,0x00,0x15,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x2e,0xbb, +0x7e,0x7d,0x5d,0x04,0x19,0x00,0x19,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x88,0xd0,0x7e,0x7d,0x5d,0x04,0x20,0x00,0x20,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0xea,0xaa, +0x7e,0x7d,0x5d,0x04,0x27,0x00,0x28,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0xfe,0x01,0x00,0x00,0x89,0x11,0x7e,0x7d,0x5d,0x04,0x2a,0x00,0x2b,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x01,0x1a,0x7e,0x7d,0x5d,0x04,0x33,0x00,0x33,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0xc2,0xc1,0x7e,0x7d,0x5d,0x04,0x36,0x00,0x36,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0xa3,0xd6,0x7e,0x7d,0x5d,0x04,0x39,0x00,0x3a,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x65,0xdf,0x7e,0x7d,0x5d,0x04, +0x3f,0x00,0x41,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0xfe,0xff,0x1f,0x00,0x1f,0x00,0x00,0x00,0xc9,0x67,0x7e,0x7d,0x5d,0x04,0x44,0x00,0x45,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x2e,0x6c,0x7e,0x7d,0x5d,0x04,0x48,0x00,0x4a,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x4f,0xf2, +0x7e,0x7d,0x5d,0x04,0x4c,0x00,0x4c,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0xf2,0x66,0x7e,0x7d,0x5d,0x04,0x4e,0x00,0x4e,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x11,0x0f, +0x7e,0x7d,0x5d,0x04,0x58,0x00,0x58,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x9a,0x49,0x7e,0x7d,0x5d,0x04,0x5a,0x00,0x5b,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x0e,0x43,0x7e,0x7d,0x5d,0x04,0x63,0x00,0x63,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0xd9,0x60,0x7e,0x7d,0x5d,0x04,0x70,0x00,0x70,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x4a,0x17,0x7e,0x7d,0x5d,0x04,0x75,0x00,0x75,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xc8,0x6d,0x7e,0x7d,0x5d,0x04,0xea,0x03,0xea,0x03,0x00,0x00,0x1e,0x00, +0x00,0x00,0xa9,0x9e,0x7e,0x7d,0x5d,0x04,0xee,0x03,0xef,0x03,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x9b,0x20,0x7e,0x7d,0x5d,0x04,0xd0,0x07,0xd7,0x07, +0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0xdc,0x10,0x7e,0x7d,0x5d,0x04,0xb8,0x0b,0xc5,0x0b,0x00,0x00,0x1f,0x00,0x00,0x00,0xfe,0xff,0x7f,0x00,0x7f,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x1f,0x00, +0x00,0x00,0xff,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1c,0x00,0x00,0x00,0xa9,0x36,0x7e,0x7d,0x5d,0x04,0xa0,0x0f,0xaa,0x0f,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0xfe,0x01,0x00,0x00,0x1e,0x00,0x00,0x00,0xfe,0xff,0x01,0x00,0xfe,0xff,0x07,0x00,0xfe,0xff,0x01,0x00,0xfe,0x07,0x00,0x00,0x1e,0x00,0x00,0x00,0xc3,0xb9, +0x7e,0x7d,0x5d,0x04,0x05,0x12,0x05,0x12,0x00,0x00,0x1f,0x00,0x00,0x00,0xd2,0x41,0x7e,0x7d,0x5d,0x04,0x07,0x12,0x07,0x12,0x00,0x00,0x1f,0x00,0x00,0x00,0xf3,0x12, +0x7e,0x7d,0x5d,0x04,0x88,0x13,0xa8,0x13,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0xf4,0x4c,0x7e,0x7d,0x5d,0x04,0x72,0x17,0x72,0x17,0x00,0x00,0x1e,0x00,0x00,0x00,0xcc,0x20, +0x7e,0x7d,0x5d,0x04,0x74,0x17,0x74,0x17,0x00,0x00,0x3f,0x00,0x00,0x00,0x47,0x46,0x7e,0x7d,0x5d,0x04,0x93,0x17,0x93,0x17,0x00,0x00,0x1e,0x00,0x00,0x00,0x8f,0xca, +0x7e,0x7d,0x5d,0x04,0x97,0x17,0x97,0x17,0x00,0x00,0x1e,0x00,0x00,0x00,0xcd,0x6c,0x7e,0x7d,0x5d,0x04,0xa4,0x17,0xb7,0x17,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00, +0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x8d,0xd1,0x7e,0x7d,0x5d,0x04,0xc0,0x17,0xc0,0x17,0x00,0x00,0x1e,0x00,0x00,0x00,0x96,0x89,0x7e,0x7d,0x5d,0x04, +0x34,0x21,0x34,0x21,0x00,0x00,0x1e,0x00,0x00,0x00,0x10,0xc3,0x7e,0x7d,0x5d,0x04,0x1c,0x25,0x25,0x25,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0xff,0x1f,0x00,0x7d,0x5e, +0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x7d,0x5e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0xfe,0x03,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x3e,0xd0,0x00,0x00, +0x90,0xed,0x7e,0x7d,0x5d,0x04,0x0b,0x28,0x0f,0x28,0x00,0x00,0x1c,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x1c,0x00,0x00,0x00, +0x71,0x86,0x7e,0x7d,0x5d,0x04,0x6e,0x28,0x89,0x28,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, +0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, +0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00, +0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x52,0x90,0x7e,0x73, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xda,0x81,0x7e,0x73,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xfe,0x0f,0x00,0x00,0xf0,0x07,0xc8,0x00,0x00,0x40, +0xc4,0x00,0x00,0x00,0x00,0xc0,0x49,0xf3,0xc7,0x5b,0x7c,0xf3,0x0b,0x01,0x00,0x00,0x00,0x20,0xec,0x00,0xcc,0x83,0x01,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x38,0x00, +0x38,0x00,0x38,0x00,0x00,0x01,0x01,0x00,0x40,0x08,0xf0,0x07,0x0c,0xf8,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x40,0x04,0x00,0xff,0xf7,0x7f,0xf0,0xfc,0xff,0xff,0xad,0xe0,0x7f,0x02,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78, +0xe0,0xff,0xff,0xff,0x48,0x1c,0x1e,0x00,0x03,0x10,0x18,0xff,0xff,0xff,0xff,0xbf,0x00,0x00,0x00,0x00,0x00,0x90,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x80,0x1b,0x80,0xff,0x5f,0x06,0x00,0x00,0x41,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xc0,0x07,0x01,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x10,0x00,0x80,0x00,0x00,0x7f,0xce,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00, +0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xf8,0x07,0x00,0x00,0x00, +0x07,0x00,0x00,0xc0,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x30,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0xb7,0xb2,0x7e,0x73,0x00,0x00, +0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x09,0x08,0x00,0x00,0x31,0x00,0x09,0x80,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xef,0x20,0xf0,0x90,0x3c,0x1d,0x60,0x04,0x00,0x00,0x4f,0x03,0xfe,0x07,0x43,0x0b,0x02, +0x01,0x00,0x00,0x07,0xf4,0x45,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x86,0x8a,0x45,0xf8,0x25,0x10,0x00,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0xc3,0x1e,0x00,0x7d,0x5e,0x00,0x4e,0x00,0xff,0x03,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x01,0x32,0x3e,0x7e,0x73,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x5d, +0x0c,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x90,0x6f,0x3b,0xfc,0x01,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0xff,0xd7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0xf0,0xff,0xe7,0xff,0xbf,0xf3,0x43,0x3f,0x02,0x00,0xe0,0xe3,0x01,0xff,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x90,0x6f,0x1f,0xfc,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0xff,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0xe0,0xe7,0xff,0xf7,0xc3,0x3f,0x01,0x00,0xe0,0xe3,0x01,0x10,0x5d,0xe6,0x7e,0x73,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x57,0x0b, +0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x01,0x00,0x7f,0x02,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0xff,0x37,0x06,0xea,0x07,0x00,0x07,0x00,0x00,0x00,0x00,0xfc,0xf0,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x77,0x00,0x00,0x7f,0x9f,0xaa,0x7e,0x73,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0xd0,0x01,0x00,0x00, +0x06,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x00,0xce,0x04,0xce,0x00,0x3f,0x00,0x3f,0x00,0xdf,0x24,0x00,0x00,0x7f,0xfc,0x3c,0x00, +0x00,0x00,0x3e,0x28,0x4e,0x50,0x05,0x12,0x51,0xe0,0x00,0x00,0xff,0xff,0xff,0xe2,0xcf,0xe1,0x7d,0x5d,0x51,0x7f,0x00,0x01,0x74,0x42,0xe0,0xac,0x34,0x7e,0x73,0x00, +0x00,0x00,0x03,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x39,0x01,0x00,0x00,0x79,0xa6,0xff,0xff,0xff,0xa1,0x1f,0x00,0xdf,0x01,0x00,0x00,0x03,0x40,0x00,0x00,0x00,0x9f, +0x00,0x00,0x00,0x00,0xc0,0x06,0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x00,0xff,0x37,0xff,0xbf,0x1b,0x05,0x00,0x01,0x2b,0x17,0x7e,0x60,0x00,0x12,0x6a,0x7e,0x60,0x01, +0x9b,0x7b,0x7e,0x82,0x00,0x00,0x00,0x55,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xb7,0x0f,0x00,0x00,0x00,0x00,0x00,0x88,0xf4,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x04,0x00,0xd8,0x8f,0xff,0x3d,0xf8,0x48,0xfa,0x3f,0x06,0x00,0x00,0x19,0x00,0x00,0x00,0x0a,0xe0,0x0f,0x22,0x00,0x00,0x00,0xf8,0x84,0x2f,0x40,0x00,0x00, +0x0a,0x80,0xff,0xef,0x01,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0xe0,0x01,0xff,0x3f,0x82,0x00,0x01, +0x7d,0x5e,0x00,0x00,0x80,0xff,0x00,0x00,0x00,0x00,0xbe,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0x0f,0xfe,0x7f,0x00,0x18,0x00,0x00,0x00,0xe0,0x01,0x00,0x00, +0xc0,0xfd,0xbf,0x95,0x03,0x00,0x00,0x00,0x00,0x00,0x80,0x81,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0xc0,0x3f,0x12,0x8c,0x04,0x00,0x60,0xc8, +0x2f,0xf8,0xe7,0xf9,0xff,0x7f,0xff,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfc,0x6f,0x00,0xc7,0x9f,0x00,0x03,0x80,0xf9,0xfa,0x0f,0x80, +0x7b,0x80,0x37,0x24,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x23,0x8c, +0x0d,0x00,0x00,0x01,0x98,0x04,0x00,0x30,0x00,0x00,0x00,0x00,0x06,0x00,0xf2,0x07,0x00,0x44,0x00,0xf8,0x1f,0x20,0x73,0x7e +}; + +extern int tty2tcp_sockfd; +ssize_t mdm_send_cmd(int ttyfd, const unsigned char *buf, size_t size) { + size_t wc = 0; + + while (wc < size) { + size_t flag = wc; + const unsigned char *cur = buf + wc; + unsigned short len = cur[2] + (((unsigned short)cur[3]) << 8) + 5; + + if (cur[0] == 0x7e && cur[1] == 0x01 && (wc + len) <= size && cur[len - 1] == 0x7e) { + flag += (len - 1); + } + else { + if (flag == 0 && buf[flag] == 0x7E) + flag++; + + while (buf[flag] != 0x7E && flag < size) + flag++; + } + + if (buf[flag] == 0x7E || flag == size) + qlog_poll_write(ttyfd, buf + wc, flag - wc + 1, 1000); + + if (tty2tcp_sockfd > 0 && (flag + 1) < size) { + size_t i = 0; + qlog_dbg("size=%zd, cur=%zd\n", size, flag - wc + 1); + for (i = 0; i < 16; i++) + printf("%02x", buf[i+wc]); + printf("\n"); + } + + wc = flag + 1; + } + + return size; +} + +static int mdm_init_filter(int ttyfd, const char *cfg) { + unsigned char *rbuf; + const size_t rbuf_size = (16*1024); + size_t cfg_size = 0; + +#if 0 + if (cfg == NULL) { + const unsigned char mdm_enter_dump1[] = { + 0x4b, 0x12, 0x18, 0x02, 0x01, 0x00, 0xd2, 0x7e + }; + const unsigned char mdm_enter_dump2[] = { + 0x7e, 0x01, 0x04, 0x00, 0x4b, 0x25, 0x03, 0x00, 0x7e + }; + qlog_dbg("send mdm dump command\n"); + mdm_send_cmd(ttyfd, mdm_enter_dump1, sizeof(mdm_enter_dump1)); + usleep(100*1000); + mdm_send_cmd(ttyfd, mdm_enter_dump2, sizeof(mdm_enter_dump2)); + return 0; + } +#endif + + rbuf = (unsigned char *)malloc(rbuf_size); + if (rbuf == NULL) { + qlog_dbg("Fail to malloc rbuf_size=%zd, errno: %d (%s)\n", rbuf_size, errno, strerror(errno)); + return -1; + } + + if (cfg) { + int cfgfd = open(cfg, O_RDONLY); + if (cfgfd < 0) { + qlog_dbg("Fail to open %s, errno : %d (%s)\n", cfg, errno, strerror(errno)); + } + + cfg_size = read(cfgfd, rbuf, rbuf_size); + close(cfgfd); + } + + if (cfg_size <= 0) { + cfg_size = sizeof(qlog_mdm_default_cfg); + memcpy(rbuf, qlog_mdm_default_cfg, cfg_size); + } + + mdm_send_cmd(ttyfd, rbuf, cfg_size); + + free(rbuf); + + return 0; +} + +qlog_ops_t mdm_qlog_ops = { + .init_filter = mdm_init_filter, +}; diff --git a/rooter/0optionalapps/qlog/src/qlog.h b/rooter/0optionalapps/qlog/src/qlog.h new file mode 100644 index 0000000..6ff8266 --- /dev/null +++ b/rooter/0optionalapps/qlog/src/qlog.h @@ -0,0 +1,44 @@ +#include +#include +#include +#ifndef __QUECTEL_QLOG_H +#define __QUECTEL_QLOG_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned int uint32_t; + +typedef struct { + int (*init_filter)(int ttyfd, const char *conf); + int (*logfile_create)(const char *logfile_dir, const char *logfile_suffix, unsigned logfile_seq); + int (*logfile_init)(int logfd, unsigned logfile_seq); + size_t (*logfile_save)(int logfd, const void *buf, size_t size); + int (*logfile_close)(int logfd); +} qlog_ops_t; + +extern qlog_ops_t mdm_qlog_ops; +extern qlog_ops_t asr_qlog_ops; +extern qlog_ops_t tty2tcp_qlog_ops; +extern int g_is_asr_chip; +extern ssize_t asr_send_cmd(int ttyfd, const unsigned char *buf, size_t size); +extern ssize_t mdm_send_cmd(int ttyfd, const unsigned char *buf, size_t size); + +extern uint32_t qlog_le32 (uint32_t v32); +extern uint64_t qlog_le64 (uint64_t v64); +extern ssize_t qlog_poll_write(int fd, const void *buf, size_t size, unsigned timeout_mesc); + +extern unsigned qlog_msecs(void); +#define qlog_dbg(fmt, arg... ) do { unsigned msec = qlog_msecs(); printf("[%03d.%03d]" fmt, msec/1000, msec%1000, ## arg); } while (0) + int sahara_catch_dump(int port_fd, const char *path_to_save_files, int do_reset); +#endif diff --git a/rooter/0optionalapps/qlog/src/sahara.c b/rooter/0optionalapps/qlog/src/sahara.c new file mode 100644 index 0000000..347f3df --- /dev/null +++ b/rooter/0optionalapps/qlog/src/sahara.c @@ -0,0 +1,660 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +unsigned int inet_addr(const char *cp); + +/* modify macro MIN +* usually we difine it as: (a) < (b) ? (a) : (b) +* but it will cause some problems, here is a case: +* MIN(i++, j++), when calling the macro above, i++ will be run two times, which is wrong. +* so we can modify it as following. +* (void)(&_a == &_b); is use to check wether the type of 'a' and 'b' is same or not. +* (void) is used to eliminated warnning. +*/ +#define MIN(a, b) ({ \ + typeof(a) _a = a; \ + typeof(b) _b = b; \ + (void)(&_a == &_b); \ + _a < _b ? _a : _b; \ + }) + +#include "sahara_protocol.h" +#include "qlog.h" + +sahara_data_t sahara_data = { + NULL, // rx_buffer + NULL, // tx_buffer + NULL, // misc_buffer + SAHARA_WAIT_HELLO, // state + 0, // timed_data_size + -1, // fd + -1, // ram_dump_image + 5, // max_ram_dump_retries + SAHARA_RAW_BUFFER_SIZE, // max_ram_dump_read + SAHARA_MODE_LAST, // mode + SAHARA_MODE_LAST, // prev_mode + 0, // command + false // ram_dump_64bit +}; + +typedef struct { + char *port_name; + int port_fd; + int rx_timeout; + size_t MAX_TO_READ; + size_t MAX_TO_WRITE; +} com_port_t; + +static com_port_t com_port = { + "/dev/ttyUSB0", // port_name + -1, // port_fd + 5, // rx_timeout + 1024 * 64, + 1024 * 64, +}; + +typedef struct { + const char *path_to_save_files; + int verbose; + int do_reset; +} kickstart_options_t; + +static kickstart_options_t kickstart_options = { + NULL, // path_to_save_files + 1, // verbose + 1, +}; + +enum LOG_LEVEL { +LOG_DEBUG = 1, +LOG_EVENT, +LOG_INFO, +LOG_STATUS, +LOG_WARN, +LOG_ERROR +}; + +extern unsigned qlog_msecs(void); +#define dbg( log_level, fmt, arg... ) do {if (kickstart_options.verbose || LOG_ERROR == log_level) { unsigned msec = qlog_msecs(); printf("[%03d.%03d]" fmt "\n", msec/1000, msec%1000, ## arg);}} while (0) + +static bool port_tx_data (void *buffer, size_t bytes_to_send) { + int temp_bytes_sent; + size_t bytes_sent = 0; + + while (bytes_sent < bytes_to_send) { + do { + temp_bytes_sent = write (com_port.port_fd, buffer + bytes_sent, MIN(bytes_to_send - bytes_sent, com_port.MAX_TO_WRITE)); + if (-1 == temp_bytes_sent && (errno == EINTR || errno == EAGAIN)) { + sleep(1); + } else { + break; + } + } while(1); + + if (temp_bytes_sent <= 0) { + dbg(LOG_ERROR, "Write returned failure %d, errno %d, System error code: %s", temp_bytes_sent, errno, strerror (errno)); + return false; + } + else { + bytes_sent += temp_bytes_sent; + } + } + + return true; +} + +static bool port_rx_data(void *buffer, size_t bytes_to_read, size_t *bytes_read) { + fd_set rfds; + struct timeval tv; + int retval; + + // Init read file descriptor + FD_ZERO (&rfds); + FD_SET (com_port.port_fd, &rfds); + + // time out initializtion. + tv.tv_sec = com_port.rx_timeout >= 0 ? com_port.rx_timeout : 0; + tv.tv_usec = 0; + + retval = select (com_port.port_fd + 1, &rfds, NULL, NULL, ((com_port.rx_timeout >= 0) ? (&tv) : (NULL))); + if (retval <= 0) { + dbg(LOG_ERROR, "select returned error: %s", strerror (errno)); + return false; + } + + retval = read (com_port.port_fd, buffer, MIN(bytes_to_read, com_port.MAX_TO_READ)); + if (retval <= 0) { + dbg(LOG_ERROR, "Read/Write File descriptor returned error: %s, error code %d", strerror (errno), retval); + return false; + } + + if (NULL != bytes_read) + *bytes_read = retval; + + return true; +} + +static bool sahara_tx_data (size_t bytes_to_send) { + return port_tx_data(sahara_data.tx_buffer, bytes_to_send); +} + +static bool sahara_rx_data(size_t bytes_to_read) { + sahara_packet_header* command_packet_header = NULL; + size_t temp_bytes_read = 0, bytes_read = 0; + + const char *boot_sahara_cmd_id_str[SAHARA_LAST_CMD_ID] = { + "SAHARA_NO_CMD_ID", // = 0x00, + " SAHARA_HELLO_ID", // = 0x01, // sent from target to host + "SAHARA_HELLO_RESP_ID", // = 0x02, // sent from host to target + "SAHARA_READ_DATA_ID", // = 0x03, // sent from target to host + "SAHARA_END_IMAGE_TX_ID", // = 0x04, // sent from target to host + "SAHARA_DONE_ID", // = 0x05, // sent from host to target + "SAHARA_DONE_RESP_ID", // = 0x06, // sent from target to host + "SAHARA_RESET_ID", // = 0x07, // sent from host to target + "SAHARA_RESET_RESP_ID", // = 0x08, // sent from target to host + "SAHARA_MEMORY_DEBUG_ID", // = 0x09, // sent from target to host + "SAHARA_MEMORY_READ_ID", // = 0x0A, // sent from host to target + "SAHARA_CMD_READY_ID", // = 0x0B, // sent from target to host + "SAHARA_CMD_SWITCH_MODE_ID", // = 0x0C, // sent from host to target + "SAHARA_CMD_EXEC_ID", // = 0x0D, // sent from host to target + "SAHARA_CMD_EXEC_RESP_ID", // = 0x0E, // sent from target to host + "SAHARA_CMD_EXEC_DATA_ID", // = 0x0F, // sent from host to target + "SAHARA_64_BITS_MEMORY_DEBUG_ID", // = 0x10, // sent from target to host + "SAHARA_64_BITS_MEMORY_READ_ID", // = 0x11, // sent from host to target + "SAHARA_64_BITS_READ_DATA_ID", // = 0x12, + }; + + if (0 == bytes_to_read) { + command_packet_header = (sahara_packet_header *) sahara_data.rx_buffer; + memset(command_packet_header, 0x00, sizeof(sahara_packet_header)); + + if (false == port_rx_data(sahara_data.rx_buffer, sizeof(sahara_packet_header), &temp_bytes_read)) + return false; + + dbg(LOG_INFO, "Read %zd bytes, command %d and packet length %d bytes", temp_bytes_read, qlog_le32(command_packet_header->command), qlog_le32(command_packet_header->length)); + if (temp_bytes_read != sizeof(sahara_packet_header)) + return false; + + if (qlog_le32(command_packet_header->command) < SAHARA_LAST_CMD_ID) { + dbg(LOG_EVENT, "RECEIVED <-- %s", boot_sahara_cmd_id_str[qlog_le32(command_packet_header->command)]); + if (false == port_rx_data(sahara_data.rx_buffer + sizeof(sahara_packet_header), qlog_le32(command_packet_header->length) - sizeof(sahara_packet_header), &temp_bytes_read)) + return false; + if (temp_bytes_read != (qlog_le32(command_packet_header->length) - sizeof(sahara_packet_header))) { + dbg(LOG_INFO, "Read %zd bytes", temp_bytes_read + sizeof(sahara_packet_header)); + return false; + } + } else { + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_CMD_UNKONOW_%d", qlog_le32(command_packet_header->command)); + return false; + } + } + else { + while (bytes_read < bytes_to_read) { + if (false == port_rx_data(sahara_data.rx_buffer + bytes_read, bytes_to_read - bytes_read, &temp_bytes_read)) { + dbg(LOG_ERROR, "bytes_read = %zd, bytes_to_read = %zd", bytes_read, bytes_to_read); + return false; + } else + bytes_read += temp_bytes_read; + } + } + + return true; +} + +static int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) { + // Perform the carry for the later subtraction by updating y. + if (x->tv_usec < y->tv_usec) { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_usec - y->tv_usec > 1000000) { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; + } + + // Compute the time remaining to wait. tv_usec is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_usec = x->tv_usec - y->tv_usec; + + // Return 1 if result is negative. + return x->tv_sec < y->tv_sec; +} + +static void time_throughput_calculate(struct timeval *start_time, struct timeval *end_time, size_t size_bytes) +{ + struct timeval result; + double TP = 0.0; + + if (size_bytes == 0) { + dbg(LOG_INFO, "Cannot calculate throughput, size is 0"); + return; + } + timeval_subtract(&result, end_time, start_time); + + TP = (double)result.tv_usec/1000000.0; + TP += (double)result.tv_sec; + + if(TP>0.0) + { + TP = (double)((double)size_bytes/TP)/(1024.0*1024.0); + dbg(LOG_STATUS, "%zd bytes transferred in %ld.%06ld seconds (%.4fMBps)", size_bytes, result.tv_sec, result.tv_usec,TP); + } + else + dbg(LOG_STATUS, "%zd bytes transferred in %ld.%06ld seconds", size_bytes, result.tv_sec, result.tv_usec); +} + +static bool send_reset_command () +{ + sahara_packet_reset *sahara_reset = (sahara_packet_reset *)sahara_data.tx_buffer; + sahara_reset->header.command = qlog_le32(SAHARA_RESET_ID); + sahara_reset->header.length = qlog_le32(sizeof(sahara_packet_reset)); + + /* Send the Reset Request */ + dbg(LOG_EVENT, "SENDING --> SAHARA_RESET"); + if (false == sahara_tx_data (sizeof(sahara_packet_reset))) { + dbg(LOG_ERROR, "Sending RESET packet failed"); + return false; + } + + return true; +} + +static bool send_memory_read_packet (uint64_t memory_table_address, uint64_t memory_table_length) { + sahara_packet_memory_read *sahara_memory_read = (sahara_packet_memory_read *)sahara_data.tx_buffer; + sahara_packet_memory_read_64bit *sahara_memory_read_64bit = (sahara_packet_memory_read_64bit *)sahara_data.tx_buffer; + + dbg(LOG_EVENT, "SENDING --> SAHARA_MEMORY_READ, address 0x%08"PRIX64", length 0x%08"PRIX64, memory_table_address, memory_table_length); + + if (true == sahara_data.ram_dump_64bit) { + sahara_memory_read_64bit->header.command = qlog_le32(SAHARA_64_BITS_MEMORY_READ_ID); + sahara_memory_read_64bit->header.length = qlog_le32(sizeof(sahara_packet_memory_read_64bit)); + sahara_memory_read_64bit->memory_addr = qlog_le64(memory_table_address); + sahara_memory_read_64bit->memory_length = qlog_le64(memory_table_length); + + /* Send the Memory Read packet */ + if (false == sahara_tx_data (sizeof(sahara_packet_memory_read_64bit))) { + dbg(LOG_ERROR, "Sending MEMORY_READ packet failed"); + return false; + } + } else { + sahara_memory_read->header.command = qlog_le32(SAHARA_MEMORY_READ_ID); + sahara_memory_read->header.length = qlog_le32(sizeof(sahara_packet_memory_read)); + sahara_memory_read->memory_addr = qlog_le32((uint32_t)memory_table_address); + sahara_memory_read->memory_length = qlog_le32((uint32_t)memory_table_length); + + /* Send the Memory Read packet */ + if (false == sahara_tx_data (sizeof(sahara_packet_memory_read))) { + dbg(LOG_ERROR, "Sending MEMORY_READ packet failed"); + return false; + } + } + + return true; +} + +static bool is_valid_memory_table(uint64_t memory_table_size) +{ + if (true == sahara_data.ram_dump_64bit && memory_table_size % sizeof(dload_debug_type_64bit) == 0) { + return true; + } + else if (false == sahara_data.ram_dump_64bit && memory_table_size % sizeof(dload_debug_type) == 0) { + return true; + } + else { + return false; + } +} + +static bool sahara_start(void) { + int retval = 0; + int num_debug_entries = -1; + int i = 0; + uint64_t memory_table_addr = 0; + uint64_t memory_table_length = 0; + + struct timeval time_start, time_end; + + sahara_packet_hello *sahara_hello = (sahara_packet_hello *)sahara_data.rx_buffer; + sahara_packet_hello_resp *sahara_hello_resp = (sahara_packet_hello_resp *)sahara_data.tx_buffer; + sahara_packet_memory_debug *sahara_memory_debug = (sahara_packet_memory_debug *)sahara_data.rx_buffer; + sahara_packet_memory_debug_64bit *sahara_memory_debug_64bit = (sahara_packet_memory_debug_64bit *)sahara_data.rx_buffer; + dload_debug_type *sahara_memory_table_rx = (dload_debug_type *)sahara_data.rx_buffer; + dload_debug_type_64bit *sahara_memory_table = (dload_debug_type_64bit *)sahara_data.misc_buffer; + sahara_packet_reset_resp *sahara_reset_resp = (sahara_packet_reset_resp *)sahara_data.rx_buffer; + + sahara_data.state = SAHARA_WAIT_HELLO; + kickstart_options.verbose = 1; + + while (1) + { + switch (sahara_data.state) + { + case SAHARA_WAIT_HELLO: + dbg(LOG_EVENT, "STATE <-- SAHARA_WAIT_HELLO"); + if (false == sahara_rx_data(0)) // size 0 means we don't know what to expect. So we'll just try to read the 8 byte header + { + sahara_tx_data(1); + if (false == sahara_rx_data(0)) + return false; + } + + //Check if the received command is a hello command + if (SAHARA_HELLO_ID != qlog_le32(sahara_hello->header.command)) { + dbg(LOG_ERROR, "Received a different command: %x while waiting for hello packet", qlog_le32(sahara_hello->header.command)); + if (false == send_reset_command ()) { + return false; + } + // set the state to SAHARA_WAIT_RESET_RESP + dbg(LOG_EVENT, "STATE <-- SAHARA_WAIT_RESET_RESP\n"); + sahara_data.state = SAHARA_WAIT_RESET_RESP; + } + else { + // Recieved hello, send the hello response + // Create a Hello request + sahara_hello_resp->header.command = qlog_le32(SAHARA_HELLO_RESP_ID); + sahara_hello_resp->header.length = qlog_le32(sizeof(sahara_packet_hello_resp)); + sahara_hello_resp->version = sahara_hello->version; //SAHARA_VERSION; + sahara_hello_resp->version_supported = sahara_hello->version_supported; //SAHARA_VERSION_SUPPORTED; + sahara_hello_resp->status = qlog_le32(SAHARA_STATUS_SUCCESS); + sahara_hello_resp->mode = sahara_hello->mode; + sahara_hello_resp->reserved0 = qlog_le32(1); + sahara_hello_resp->reserved1 = qlog_le32(2); + sahara_hello_resp->reserved2 = qlog_le32(3); + sahara_hello_resp->reserved3 = qlog_le32(4); + sahara_hello_resp->reserved4 = qlog_le32(5); + sahara_hello_resp->reserved5 = qlog_le32(6); + + switch (qlog_le32(sahara_hello->mode)) { + case SAHARA_MODE_IMAGE_TX_PENDING: + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_IMAGE_TX_PENDING"); + break; + case SAHARA_MODE_IMAGE_TX_COMPLETE: + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_IMAGE_TX_COMPLETE"); + break; + case SAHARA_MODE_MEMORY_DEBUG: + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_MEMORY_DEBUG"); + break; + case SAHARA_MODE_COMMAND: + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_COMMAND"); + break; + default: + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MODE_0x%x", qlog_le32(sahara_hello->mode)); + break; + } + + if (qlog_le32(sahara_hello->mode) != sahara_data.mode) { + dbg(LOG_ERROR, "Not expect module state "); + return false; + } + + /*Send the Hello Resonse Request*/ + dbg(LOG_EVENT, "SENDING --> SAHARA_HELLO_RESPONSE"); + if (false == sahara_tx_data (sizeof(sahara_packet_hello_resp))) + { + dbg(LOG_ERROR, "Tx Sahara Data Failed "); + return false; + } + sahara_data.state = SAHARA_WAIT_COMMAND; + } + break; + + case SAHARA_WAIT_COMMAND: + dbg(LOG_INFO, "STATE <-- SAHARA_WAIT_COMMAND"); + if (false == sahara_rx_data(0)) + return false; + + // Check if it is an end of image Tx + if (SAHARA_MEMORY_DEBUG_ID == qlog_le32(((sahara_packet_header *)sahara_data.rx_buffer)->command) + || SAHARA_64_BITS_MEMORY_DEBUG_ID == qlog_le32(((sahara_packet_header *)sahara_data.rx_buffer)->command)) { + dbg(LOG_EVENT, "RECEIVED <-- SAHARA_MEMORY_DEBUG"); + + if (SAHARA_64_BITS_MEMORY_DEBUG_ID == qlog_le32(((sahara_packet_header *)sahara_data.rx_buffer)->command)) { + sahara_data.ram_dump_64bit = true; + dbg(LOG_EVENT, "Using 64 bit RAM dump mode"); + memory_table_addr = qlog_le64(sahara_memory_debug_64bit->memory_table_addr); + memory_table_length = qlog_le64(sahara_memory_debug_64bit->memory_table_length); + } + else { + sahara_data.ram_dump_64bit = false; + memory_table_addr = qlog_le32(sahara_memory_debug->memory_table_addr); + memory_table_length = qlog_le32(sahara_memory_debug->memory_table_length); + } + + dbg(LOG_INFO, "Memory Table Address: 0x%08"PRIX64", Memory Table Length: 0x%08"PRIX64, memory_table_addr, memory_table_length); + + if (false == is_valid_memory_table(memory_table_length)) { + dbg(LOG_ERROR, "Invalid memory table received"); + if (false == send_reset_command ()) { + return false; + } + sahara_data.state = SAHARA_WAIT_RESET_RESP; + break; + } + + if (memory_table_length > 0) { + if (false == send_memory_read_packet(memory_table_addr, memory_table_length)) { + return false; + } + + if (memory_table_length > SAHARA_RAW_BUFFER_SIZE) { + dbg(LOG_ERROR, "Memory table length is greater than size of intermediate buffer"); + return false; + } + } + dbg(LOG_EVENT, "STATE <-- SAHARA_WAIT_MEMORY_TABLE"); + sahara_data.state = SAHARA_WAIT_MEMORY_TABLE; + } + else { + dbg(LOG_ERROR, "Received an unknown command: %d ", qlog_le32(((sahara_packet_header *)sahara_data.rx_buffer)->command)); + if (SAHARA_HELLO_ID == qlog_le32(((sahara_packet_header *)sahara_data.rx_buffer)->command)) + continue; + if (false == send_reset_command ()) { + return false; + } + // set the state to SAHARA_WAIT_RESET_RESP + dbg(LOG_EVENT, "STATE <-- SAHARA_WAIT_RESET_RESP"); + sahara_data.state = SAHARA_WAIT_RESET_RESP; + } + break; + + case SAHARA_WAIT_MEMORY_TABLE: + dbg(LOG_INFO, "STATE <-- SAHARA_WAIT_MEMORY_TABLE"); + num_debug_entries = 0; + if (memory_table_length > 0) { + if (false == sahara_rx_data((size_t)memory_table_length)) { + return false; + } + dbg(LOG_INFO, "Memory Debug table received"); + + if (true == sahara_data.ram_dump_64bit) { + memcpy (sahara_data.misc_buffer, sahara_data.rx_buffer, (size_t)memory_table_length); + num_debug_entries = (int)(memory_table_length/sizeof(dload_debug_type_64bit)); + } + else { + num_debug_entries = (int)(memory_table_length/sizeof(dload_debug_type)); + if (num_debug_entries * sizeof(dload_debug_type_64bit) > SAHARA_RAW_BUFFER_SIZE) { + dbg(LOG_ERROR, "Length of memory table converted to 64-bit entries is greater than size of intermediate buffer"); + return false; + } + + for (i = 0; i < num_debug_entries; ++i) { + sahara_memory_table[i].save_pref = (uint64_t) qlog_le32(sahara_memory_table_rx[i].save_pref); + sahara_memory_table[i].mem_base = (uint64_t) qlog_le32(sahara_memory_table_rx[i].mem_base); + sahara_memory_table[i].length = (uint64_t) qlog_le32(sahara_memory_table_rx[i].length); + strncpy(sahara_memory_table[i].filename, sahara_memory_table_rx[i].filename, DLOAD_DEBUG_STRLEN_BYTES); + strncpy(sahara_memory_table[i].desc, sahara_memory_table_rx[i].desc, DLOAD_DEBUG_STRLEN_BYTES); + } // end for (i = 0; i < num_debug_entries; ++i) + } + } + + for(i = 0; i < num_debug_entries; i++) { + dbg(LOG_EVENT, "Base 0x%08"PRIX64" Len 0x%08"PRIX64", '%s', '%s'", sahara_memory_table[i].mem_base, sahara_memory_table[i].length, sahara_memory_table[i].filename, sahara_memory_table[i].desc); + } + sahara_data.state = SAHARA_WAIT_MEMORY_REGION; + break; + + case SAHARA_WAIT_MEMORY_REGION: + dbg(LOG_INFO, "STATE <-- SAHARA_WAIT_MEMORY_REGION"); + for(i = 0; i < num_debug_entries; i++) { + uint64_t cur = 0; + int fd = -1; + char full_filename[255] = {0}; + if (kickstart_options.path_to_save_files) { + strcpy(full_filename, kickstart_options.path_to_save_files); + strcat(full_filename, "/"); + } + strcat(full_filename, sahara_memory_table[i].filename); + + fd = open(full_filename, O_CREAT | O_WRONLY | O_TRUNC, 0444); + if (fd==-1) { + dbg(LOG_ERROR, "ERROR: Your file '%s' does not exist or cannot be created\n\n",sahara_memory_table[num_debug_entries].filename); + exit(0); + } + gettimeofday(&time_start, NULL); + + while (cur < sahara_memory_table[i].length) { + uint64_t len = MIN((uint32_t)(sahara_memory_table[i].length - cur), sahara_data.max_ram_dump_read); + + if (len < sahara_data.max_ram_dump_read || cur == 0 || (cur%(16*1024*1024)) == 0) + kickstart_options.verbose = 1; + else + kickstart_options.verbose = 0; + + retval = send_memory_read_packet(sahara_memory_table[i].mem_base + cur, len); + if (false == retval) { + return false; + } + + retval = sahara_rx_data((size_t)len); + if (false == retval) { + system("fuser /dev/ttyUSB0"); + if ( sahara_data.max_ram_dump_read > (16*1024)) { + sahara_data.max_ram_dump_read = sahara_data.max_ram_dump_read / 2; + continue; + } + return false; + } + + cur += len; + + retval = write(fd, sahara_data.rx_buffer, (unsigned int)len); + if (retval < 0) { + dbg(LOG_ERROR, "file write failed: %s", strerror(errno)); + return false; + } + if ((uint32_t) retval != len) { + dbg(LOG_WARN, "Wrote only %d of 0x%08"PRIX64" bytes", retval, memory_table_length); + } + } + + + kickstart_options.verbose = 1; + dbg(LOG_STATUS, "Received file '%s'", sahara_memory_table[i].filename); + close(fd); + gettimeofday(&time_end, NULL); + time_throughput_calculate(&time_start, &time_end, sahara_memory_table[i].length); + } + + if ( kickstart_options.do_reset) { + if (false == send_reset_command ()) { + return false; + } + sahara_data.state = SAHARA_WAIT_RESET_RESP; + } else { + return true; + } + break; + + case SAHARA_WAIT_DONE_RESP: + dbg(LOG_EVENT, "STATE <-- SAHARA_WAIT_DONE_RESP"); + return false; + break; + + case SAHARA_WAIT_RESET_RESP: + dbg(LOG_EVENT, "STATE <-- SAHARA_WAIT_RESET_RESP"); + if (true == sahara_rx_data(0)) { + if (SAHARA_RESET_RESP_ID != qlog_le32(sahara_reset_resp->header.command)) { + dbg(LOG_INFO,"Waiting for reset response code %i, received %i instead.", SAHARA_RESET_RESP_ID, qlog_le32(sahara_reset_resp->header.command)); + continue; + } + } else { + if (SAHARA_RESET_RESP_ID == qlog_le32(sahara_reset_resp->header.command)) { + dbg(LOG_INFO,"Get reset response code %i", sahara_reset_resp->header.command); + return true; + } else { + dbg(LOG_ERROR, "read failed: Linux system error: %s", strerror(errno)); + return false; + } + } + + return true; + break; + + default: + dbg(LOG_ERROR, "Unrecognized state %d", sahara_data.state); + return false; + } /* end switch */ + } /* end while (1) */ +} + + int sahara_catch_dump(int port_fd, const char *path_to_save_files, int do_reset) { + int retval; + + sahara_data.mode = SAHARA_MODE_MEMORY_DEBUG; + com_port.port_fd = port_fd; + kickstart_options.path_to_save_files = path_to_save_files; + kickstart_options.do_reset = do_reset; + + sahara_data.rx_buffer = malloc (SAHARA_RAW_BUFFER_SIZE); + sahara_data.tx_buffer = malloc (2048); + sahara_data.misc_buffer = malloc (2048); + + if (NULL == sahara_data.rx_buffer || NULL == sahara_data.tx_buffer || NULL == sahara_data.misc_buffer) { + dbg(LOG_ERROR, "Failed to allocate sahara buffers"); + return false; + } + + retval = sahara_start(); + if (false == retval) { + dbg(LOG_ERROR, "Sahara protocol error"); + } + else { + dbg(LOG_ERROR, "Sahara protocol completed"); + } + + free(sahara_data.rx_buffer); + free(sahara_data.tx_buffer); + free(sahara_data.misc_buffer); + + sahara_data.rx_buffer = sahara_data.tx_buffer = sahara_data.misc_buffer = NULL; + + if (retval == false) + dbg(LOG_INFO, "Catch DUMP using Sahara protocol failed\n\n"); + else + dbg(LOG_INFO, "Catch DUMP using Sahara protocol successful\n\n"); + + return retval; +} diff --git a/rooter/0optionalapps/qlog/src/sahara_protocol.h b/rooter/0optionalapps/qlog/src/sahara_protocol.h new file mode 100644 index 0000000..0db7989 --- /dev/null +++ b/rooter/0optionalapps/qlog/src/sahara_protocol.h @@ -0,0 +1,510 @@ +/*=========================================================================== + * FILE: + * sahara_packet.h + * + * DESCRIPTION: + * Sahara protocol states and structure declaration. + * + * Copyright (C) 2012 Qualcomm Technologies, Inc. All rights reserved. + * Qualcomm Technologies Proprietary/GTDR + * + * All data and information contained in or disclosed by this document is + * confidential and proprietary information of Qualcomm Technologies, Inc. and all + * rights therein are expressly reserved. By accepting this material the + * recipient agrees that this material and the information contained therein + * is held in confidence and in trust and will not be used, copied, reproduced + * in whole or in part, nor its contents revealed in any manner to others + * without the express written permission of Qualcomm Technologies, Inc. + * =========================================================================== + * + * sahara_packet.h : Sahara protocol states and structure declaration. + * ========================================================================================== + * $Header: //components/rel/boot.bf/3.1.4/boot_images/core/storage/tools/QSaharaServer/src/sahara_protocol.h#1 $ + * $DateTime: 2017/02/21 04:58:32 $ + * $Author: pwbldsvc $ + * + * Edit History: + * YYYY-MM-DD who why + * ----------------------------------------------------------------------------- + * 2010-09-28 ng Added command mode support + * 2010-10-18 ab Added memory debug mode support + * + * Copyright 2012 by Qualcomm Technologies, Inc. All Rights Reserved. + * + *========================================================================================== + */ + +#ifndef SAHARA_PROTOCOL_H +#define SAHARA_PROTOCOL_H + +/*=========================================================================== + * + * INCLUDE FILES + * + * ===========================================================================*/ + +/*=========================================================================== + * + * PUBLIC DATA DECLARATIONS + * + * ===========================================================================*/ +// Sahara Protocol Version +#define SAHARA_VERSION 2 +#define SAHARA_VERSION_SUPPORTED 4 + +/*Maximum 1 megabyte tx buffer size*/ +#define SAHARA_RAW_BUFFER_SIZE (64*1024) + +// Sahara command IDs +typedef enum +{ + SAHARA_NO_CMD_ID = 0x00, + SAHARA_HELLO_ID = 0x01, // sent from target to host + SAHARA_HELLO_RESP_ID = 0x02, // sent from host to target + SAHARA_READ_DATA_ID = 0x03, // sent from target to host + SAHARA_END_IMAGE_TX_ID = 0x04, // sent from target to host + SAHARA_DONE_ID = 0x05, // sent from host to target + SAHARA_DONE_RESP_ID = 0x06, // sent from target to host + SAHARA_RESET_ID = 0x07, // sent from host to target + SAHARA_RESET_RESP_ID = 0x08, // sent from target to host + SAHARA_MEMORY_DEBUG_ID = 0x09, // sent from target to host + SAHARA_MEMORY_READ_ID = 0x0A, // sent from host to target + SAHARA_CMD_READY_ID = 0x0B, // sent from target to host + SAHARA_CMD_SWITCH_MODE_ID = 0x0C, // sent from host to target + SAHARA_CMD_EXEC_ID = 0x0D, // sent from host to target + SAHARA_CMD_EXEC_RESP_ID = 0x0E, // sent from target to host + SAHARA_CMD_EXEC_DATA_ID = 0x0F, // sent from host to target + SAHARA_64_BITS_MEMORY_DEBUG_ID = 0x10, // sent from target to host + SAHARA_64_BITS_MEMORY_READ_ID = 0x11, // sent from host to target + SAHARA_64_BITS_READ_DATA_ID = 0x12, + // place all new commands above this + SAHARA_LAST_CMD_ID, + SAHARA_MAX_CMD_ID = 0x7FFFFFFF // To ensure 32-bits wide +} boot_sahara_cmd_id; + +typedef enum { + SAHARA_IMAGE_TYPE_BINARY = 0, /* Binary format */ + SAHARA_IMAGE_TYPE_ELF, /* ELF format */ + SAHARA_IMAGE_UNKNOWN = 0x7FFFFFFF /* To ensure 32-bits wide */ +} boot_sahara_image; + +// Status codes for Sahara +typedef enum +{ + // Success + SAHARA_STATUS_SUCCESS = 0x00, + + // Invalid command received in current state + SAHARA_NAK_INVALID_CMD = 0x01, + + // Protocol mismatch between host and target + SAHARA_NAK_PROTOCOL_MISMATCH = 0x02, + + // Invalid target protocol version + SAHARA_NAK_INVALID_TARGET_PROTOCOL = 0x03, + + // Invalid host protocol version + SAHARA_NAK_INVALID_HOST_PROTOCOL = 0x04, + + // Invalid packet size received + SAHARA_NAK_INVALID_PACKET_SIZE = 0x05, + + // Unexpected image ID received + SAHARA_NAK_UNEXPECTED_IMAGE_ID = 0x06, + + // Invalid image header size received + SAHARA_NAK_INVALID_HEADER_SIZE = 0x07, + + // Invalid image data size received + SAHARA_NAK_INVALID_DATA_SIZE = 0x08, + + // Invalid image type received + SAHARA_NAK_INVALID_IMAGE_TYPE = 0x09, + + // Invalid tranmission length + SAHARA_NAK_INVALID_TX_LENGTH = 0x0A, + + // Invalid reception length + SAHARA_NAK_INVALID_RX_LENGTH = 0x0B, + + // General transmission or reception error + SAHARA_NAK_GENERAL_TX_RX_ERROR = 0x0C, + + // Error while transmitting READ_DATA packet + SAHARA_NAK_READ_DATA_ERROR = 0x0D, + + // Cannot receive specified number of program headers + SAHARA_NAK_UNSUPPORTED_NUM_PHDRS = 0x0E, + + // Invalid data length received for program headers + SAHARA_NAK_INVALID_PDHR_SIZE = 0x0F, + + // Multiple shared segments found in ELF image + SAHARA_NAK_MULTIPLE_SHARED_SEG = 0x10, + + // Uninitialized program header location + SAHARA_NAK_UNINIT_PHDR_LOC = 0x11, + + // Invalid destination address + SAHARA_NAK_INVALID_DEST_ADDR = 0x12, + + // Invalid data size receieved in image header + SAHARA_NAK_INVALID_IMG_HDR_DATA_SIZE = 0x13, + + // Invalid ELF header received + SAHARA_NAK_INVALID_ELF_HDR = 0x14, + + // Unknown host error received in HELLO_RESP + SAHARA_NAK_UNKNOWN_HOST_ERROR = 0x15, + + // Timeout while receiving data + SAHARA_NAK_TIMEOUT_RX = 0x16, + + // Timeout while transmitting data + SAHARA_NAK_TIMEOUT_TX = 0x17, + + // Invalid mode received from host + SAHARA_NAK_INVALID_HOST_MODE = 0x18, + + // Invalid memory read access + SAHARA_NAK_INVALID_MEMORY_READ = 0x19, + + // Host cannot handle read data size requested + SAHARA_NAK_INVALID_DATA_SIZE_REQUEST = 0x1A, + + // Memory debug not supported + SAHARA_NAK_MEMORY_DEBUG_NOT_SUPPORTED = 0x1B, + + // Invalid mode switch + SAHARA_NAK_INVALID_MODE_SWITCH = 0x1C, + + // Failed to execute command + SAHARA_NAK_CMD_EXEC_FAILURE = 0x1D, + + // Invalid parameter passed to command execution + SAHARA_NAK_EXEC_CMD_INVALID_PARAM = 0x1E, + + // Unsupported client command received + SAHARA_NAK_EXEC_CMD_UNSUPPORTED = 0x1F, + + // Invalid client command received for data response + SAHARA_NAK_EXEC_DATA_INVALID_CLIENT_CMD = 0x20, + + // Failed to authenticate hash table + SAHARA_NAK_HASH_TABLE_AUTH_FAILURE = 0x21, + + // Failed to verify hash for a given segment of ELF image + SAHARA_NAK_HASH_VERIFICATION_FAILURE = 0x22, + + // Failed to find hash table in ELF image + SAHARA_NAK_HASH_TABLE_NOT_FOUND = 0x23, + + // Place all new error codes above this + SAHARA_NAK_LAST_CODE, + + SAHARA_NAK_MAX_CODE = 0x7FFFFFFF // To ensure 32-bits wide +} boot_sahara_status; + +// Status of all image transfers +typedef enum +{ + SAHARA_MODE_IMAGE_TX_PENDING = 0x0, + SAHARA_MODE_IMAGE_TX_COMPLETE = 0x1, + SAHARA_MODE_MEMORY_DEBUG = 0x2, + SAHARA_MODE_COMMAND = 0x3, + + // place all new commands above this + SAHARA_MODE_LAST, + SAHARA_MODE_MAX = 0x7FFFFFFF +} boot_sahara_mode; + +// Executable commands when target is in command mode +typedef enum +{ + SAHARA_EXEC_CMD_NOP = 0x00, + SAHARA_EXEC_CMD_SERIAL_NUM_READ = 0x01, + SAHARA_EXEC_CMD_MSM_HW_ID_READ = 0x02, + SAHARA_EXEC_CMD_OEM_PK_HASH_READ = 0x03, + SAHARA_EXEC_CMD_SWITCH_DMSS = 0x04, + SAHARA_EXEC_CMD_SWITCH_STREAMING = 0x05, + SAHARA_EXEC_CMD_READ_DEBUG_DATA = 0x06, + + // place all new commands above this + SAHARA_EXEC_CMD_LAST, + SAHARA_EXEC_CMD_MAX = 0x7FFFFFFF +} boot_sahara_exec_cmd_id; + +/* Sahara Protocol states */ +typedef enum { + SAHARA_WAIT_HELLO, + SAHARA_WAIT_COMMAND, + SAHARA_WAIT_RESET_RESP, + SAHARA_WAIT_DONE_RESP, + SAHARA_WAIT_MEMORY_READ, + SAHARA_WAIT_CMD_EXEC_RESP, + SAHARA_WAIT_MEMORY_TABLE, + SAHARA_WAIT_MEMORY_REGION, +} boot_sahara_state; + +/* ============================================================================= */ +/* Sahara protocol packet defintions */ +/* ============================================================================= */ + +typedef struct +{ + uint32_t command; // command ID + uint32_t length; // packet length incl command and length +} sahara_packet_header; + +// HELLO command packet type - sent from target to host +// indicates start of protocol on target side +typedef struct +{ + sahara_packet_header header; + uint32_t version; // target protocol version number + uint32_t version_supported; // minimum protocol version number supported + // on target + uint32_t cmd_packet_length; // maximum packet size supported for command + // packets + uint32_t mode; // expected mode of target operation + uint32_t reserved0; // reserved field + uint32_t reserved1; // reserved field + uint32_t reserved2; // reserved field + uint32_t reserved3; // reserved field + uint32_t reserved4; // reserved field + uint32_t reserved5; // reserved field +} sahara_packet_hello; + +// HELLO_RESP command packet type - sent from host to target +// response to hello, protocol version running on host and status sent +typedef struct +{ + sahara_packet_header header; + uint32_t version; // host protocol version number + uint32_t version_supported; // minimum protocol version number supported + // on host + uint32_t status; // OK or error condition + uint32_t mode; // mode of operation for target to execute + uint32_t reserved0; // reserved field + uint32_t reserved1; // reserved field + uint32_t reserved2; // reserved field + uint32_t reserved3; // reserved field + uint32_t reserved4; // reserved field + uint32_t reserved5; // reserved field +} sahara_packet_hello_resp; + +// READ_DATA command packet type - sent from target to host +// sends data segment offset and length to be read from current host +// image file +typedef struct +{ + sahara_packet_header header; + uint32_t image_id; // ID of image to be transferred + uint32_t data_offset; // offset into image file to read data from + uint32_t data_length; // length of data segment to be retreived + // from image file +} sahara_packet_read_data; + +// READ_DATA_64 command packet type - sent from target to host +// sends data segment offset and length to be read from current host +// image file +/* +#ifdef WINDOWSPC +#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) ) +PACK( +typedef struct // note for gcc use __attribute__((__packed__)) +{ + sahara_packet_header header; + uint32_t image_id; // ID of image to be transferred + uint64_t data_offset; // offset into image file to read data from + uint32_t data_length; // length of data segment to be retreived + // from image file +} sahara_packet_read_data_64bit; +); +#else +typedef __attribute__((__packed__)) struct +{ + sahara_packet_header header; + uint32_t image_id; // ID of image to be transferred + uint64_t data_offset; // offset into image file to read data from + uint32_t data_length; // length of data segment to be retreived + // from image file +} sahara_packet_read_data_64bit; +#endif +*/ +typedef struct +{ + sahara_packet_header header; + uint64_t image_id; // ID of image to be transferred + uint64_t data_offset; // offset into image file to read data from + uint64_t data_length; // length of data segment to be retreived + // from image file +} sahara_packet_read_data_64bit; + +// END_IMAGE_TX command packet type - sent from target to host +// indicates end of a single image transfer and status of transfer +typedef struct +{ + sahara_packet_header header; + uint32_t image_id; // ID of image to be transferred + uint32_t status; // OK or error condition +} sahara_packet_end_image_tx; + +// DONE packet type - sent from host to target +// indicates end of single image transfer +typedef struct +{ + sahara_packet_header header; +} sahara_packet_done; + +// DONE_RESP packet type - sent from target to host +// indicates end of all image transfers +typedef struct +{ + sahara_packet_header header; + uint32_t image_tx_status; // indicates if all images have been + // transferred; + // 0 = IMAGE_TX_PENDING + // 1 = IMAGE_TX_COMPLETE +} sahara_packet_done_resp; + +// RESET packet type - sent from host to target +// indicates to target to reset +typedef struct +{ + sahara_packet_header header; +} sahara_packet_reset; + +// RESET_RESP packet type - sent from target to host +// indicates to host that target has reset +typedef struct +{ + sahara_packet_header header; +} sahara_packet_reset_resp; + +// MEMORY_DEBUG packet type - sent from target to host +// sends host the location and length of memory region table +typedef struct +{ + sahara_packet_header header; + uint32_t memory_table_addr; // location of memory region table + uint32_t memory_table_length; // length of memory table +} sahara_packet_memory_debug; +typedef struct +{ + sahara_packet_header header; + uint64_t memory_table_addr; // location of memory region table + uint64_t memory_table_length; // length of memory table +} sahara_packet_memory_debug_64bit; + +// MEMORY_READ packet type - sent from host to target +// sends memory address and length to read from target memory +typedef struct +{ + sahara_packet_header header; + uint32_t memory_addr; // memory location to read from + uint32_t memory_length; // length of data to send +} sahara_packet_memory_read; +typedef struct +{ + sahara_packet_header header; + uint64_t memory_addr; // memory location to read from + uint64_t memory_length; // length of data to send +} sahara_packet_memory_read_64bit; + +// CMD_READY packet type - sent from target to host +// indicates to host that target is ready to accept commands +typedef struct +{ + sahara_packet_header header; +} sahara_packet_cmd_ready; + +// CMD_SWITCH_MODE packet type - sent from host to target +// indicates to target to switch modes +typedef struct +{ + sahara_packet_header header; + uint32_t mode; // mode of operation for target to execute +} sahara_packet_cmd_switch_mode; + +// CMD_EXEC packet type - sent from host to target +// indicates to target to execute given client_command +typedef struct +{ + sahara_packet_header header; + uint32_t client_command; // command ID for target Sahara client to + // execute +} sahara_packet_cmd_exec; + +// CMD_EXEC_RESP packet type - sent from host to target +// indicates to host that target has successfully executed command +// and length of data response +typedef struct +{ + sahara_packet_header header; + uint32_t client_command; // command ID for target Sahara client to + // execute + uint32_t resp_length; // length of response returned from command + // execution +} sahara_packet_cmd_exec_resp; + +// CMD_EXEC_DATA packet type - sent from target to host +// indicates that host is ready to receive data after command execution +typedef struct +{ + sahara_packet_header header; + uint32_t client_command; // command ID for target Sahara client to + // execute +} sahara_packet_cmd_exec_data; + +#define DLOAD_DEBUG_STRLEN_BYTES 20 +typedef struct +{ + uint32_t save_pref; + uint32_t mem_base; + uint32_t length; + char desc[DLOAD_DEBUG_STRLEN_BYTES]; + char filename[DLOAD_DEBUG_STRLEN_BYTES]; +} dload_debug_type; + +typedef struct +{ + uint64_t save_pref; //force 8 bytes alignment + uint64_t mem_base; + uint64_t length; + char desc[DLOAD_DEBUG_STRLEN_BYTES]; + char filename[DLOAD_DEBUG_STRLEN_BYTES]; +} dload_debug_type_64bit; + +typedef struct { + /* buffer for sahara rx */ + void* rx_buffer; + + /* buffer for sahara tx */ + void* tx_buffer; + + /* buffer for memory table */ + void* misc_buffer; + + /* Sahara state */ + boot_sahara_state state; + + size_t timed_data_size; + + // handle to input image + int fd; + + int ram_dump_image; + + int max_ram_dump_retries; + + uint32_t max_ram_dump_read; + + boot_sahara_mode mode; + boot_sahara_mode prev_mode; + + unsigned int command; + bool ram_dump_64bit; + +} sahara_data_t; +#endif /* SAHARA_PACKET_H */ diff --git a/rooter/0optionalapps/qlog/src/tty2tcp.c b/rooter/0optionalapps/qlog/src/tty2tcp.c new file mode 100644 index 0000000..9d3b6e4 --- /dev/null +++ b/rooter/0optionalapps/qlog/src/tty2tcp.c @@ -0,0 +1,174 @@ +#include "qlog.h" + +unsigned int inet_addr(const char *cp); +char *inet_ntoa(struct in_addr in); + +static int wait_tcp_client_connect(int tcp_port) { + int sockfd, n, connfd; + struct sockaddr_in serveraddr; + struct sockaddr_in clientaddr; + int reuse_addr = 1; + size_t sin_size; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd == -1) + { + qlog_dbg("Create socket fail!\n"); + return 0; + } + + memset(&serveraddr, 0, sizeof(serveraddr)); + serveraddr.sin_family = AF_INET; + serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); + serveraddr.sin_port = htons(tcp_port); + + qlog_dbg("Starting the TCP server(%d)...\n", tcp_port); + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr)); + + n = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); + if (n == -1) + { + qlog_dbg("bind fail! errno: %d\n", errno); + close(sockfd); + return 0; + } + qlog_dbg("bind OK!\n"); + + n = listen(sockfd, 1); + if (n == -1) + { + qlog_dbg("listen fail! errno: %d\n", errno); + close(sockfd); + return 0; + } + qlog_dbg("listen OK!\nWaiting the TCP Client...\n"); + + sin_size = sizeof(struct sockaddr_in); + connfd = accept(sockfd, (struct sockaddr *)&clientaddr, (socklen_t *)&sin_size); + close(sockfd); + if (connfd == -1) + { + qlog_dbg("accept fail! errno: %d\n", errno); + return -1; + } + + qlog_dbg("TCP Client %s:%d connect\n", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port); + + return connfd; +} + +int tty2tcp_sockfd = -1; +static int tty2tcp_ttyfd = -1; +static int tty2tcp_tcpport = 9000; + +static void *tcp_sock_read_Loop(void *arg) { + int sockfd = tty2tcp_sockfd; + int ttyfd = tty2tcp_ttyfd; + void *rbuf; + const size_t rbuf_size = (4*1024); + + rbuf = malloc(rbuf_size); + if (rbuf == NULL) { + qlog_dbg("Fail to malloc rbuf_size=%zd, errno: %d (%s)\n", rbuf_size, errno, strerror(errno)); + return NULL; + } + + while (sockfd > 0) { + ssize_t rc, wc; + int ret; + struct pollfd pollfds[] = {{sockfd, POLLIN, 0}}; + + ret = poll(pollfds, 1, -1); + + if (ret <= 0) { + qlog_dbg("poll(ttyfd) =%d, errno: %d (%s)\n", ret, errno, strerror(errno)); + break; + } + + if (pollfds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { + tty2tcp_sockfd = -1; + close(sockfd); + qlog_dbg("ttyfd revents = %04x\n", pollfds[0].revents); + sockfd = tty2tcp_sockfd = wait_tcp_client_connect(tty2tcp_tcpport); + } + + if (pollfds[0].revents & (POLLIN)) { + rc = read(sockfd, rbuf, rbuf_size); + + if(rc > 0) { + if (g_is_asr_chip) + wc = asr_send_cmd(ttyfd, rbuf, rc); + else + wc = mdm_send_cmd(ttyfd, rbuf, rc); + + if (wc != rc) { + //qlog_dbg("ttyfd write fail %zd/%zd, break\n", wc, rc); + //break; + } + } + else + { + tty2tcp_sockfd = -1; + close(sockfd); + qlog_dbg("sockfd recv %zd Bytes. maybe terminae by peer!\n", rc); + sockfd = tty2tcp_sockfd = wait_tcp_client_connect(tty2tcp_tcpport); + } + } + } + + free(rbuf); + close(ttyfd); + tty2tcp_sockfd = -1; + qlog_dbg("%s exit\n", __func__); + + return NULL; +} + +static int tty2tcp_init_filter(int ttyfd, const char *cfg) { + int tcp_port = 9000; + int sockfd = -1; + pthread_t tid; + pthread_attr_t attr; + + if (cfg) + tcp_port = atoi(cfg); + + tty2tcp_tcpport = tcp_port; + sockfd = wait_tcp_client_connect(tcp_port); + + if (sockfd <= 0) + return -1; + + fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK); + + pthread_attr_init (&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + tty2tcp_sockfd = sockfd; + tty2tcp_ttyfd = ttyfd; + pthread_create(&tid, &attr, tcp_sock_read_Loop, &attr); + + return 0; +} + +static int tty2tcp_logfile_create(const char *logfile_dir, const char *logfile_suffix, unsigned logfile_seq) { + return 1; +} + +static size_t tty2tcp_logfile_save(int logfd, const void *buf, size_t size) { + if (tty2tcp_sockfd > 0) + return qlog_poll_write(tty2tcp_sockfd, buf, size, 200); + return size; +} + +static int tty2tcp_logfile_close(int logfd) { + return 0; +} + +qlog_ops_t tty2tcp_qlog_ops = { + .init_filter = tty2tcp_init_filter, + .logfile_create = tty2tcp_logfile_create, + .logfile_save = tty2tcp_logfile_save, + .logfile_close = tty2tcp_logfile_close, +}; diff --git a/rooter/0optionalapps/udp-tunnel/Makefile b/rooter/0optionalapps/udp-tunnel/Makefile new file mode 100644 index 0000000..4d568b5 --- /dev/null +++ b/rooter/0optionalapps/udp-tunnel/Makefile @@ -0,0 +1,40 @@ +# +# Copyright (C) 2011-2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=udp-tunnel +PKG_RELEASE:=1 + +PKG_FLAGS:=nonshared + +include $(INCLUDE_DIR)/package.mk + +define Package/udp-tunnel + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + TITLE:=UDPTunnel + MAINTAINER:=Dairyman +endef + +define Package/udp-tunnel/description + UDPTunnel +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" \ + CFLAGS="$(TARGET_CFLAGS) -Wall" +endef + +define Package/udp-tunnel/install + $(INSTALL_DIR) $(1)/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/udptunnel $(1)/sbin/udptunnel +endef + +$(eval $(call BuildPackage,udp-tunnel)) diff --git a/rooter/0optionalapps/udp-tunnel/src/Makefile b/rooter/0optionalapps/udp-tunnel/src/Makefile new file mode 100644 index 0000000..0a70e29 --- /dev/null +++ b/rooter/0optionalapps/udp-tunnel/src/Makefile @@ -0,0 +1,36 @@ +prefix = /usr/local + +CFLAGS ?= -g -O2 + +INSTALL ?= install +PKG_CONFIG ?= pkg-config + +ifeq ($(shell $(PKG_CONFIG) --exists libsystemd || echo NO),) +DEFS += -DHAVE_SYSTEMD_SD_DAEMON_H $(shell $(PKG_CONFIG) --cflags libsystemd) +LDADD += $(shell $(PKG_CONFIG) --libs libsystemd) +endif + +CPPFLAGS += $(DEFS) $(INCLUDES) + +OBJECTS := log.o network.o utils.o udptunnel.o + +all: depend udptunnel + +install: + $(INSTALL) -d $(BASEDIR)$(prefix)/sbin/ + $(INSTALL) -m 0755 udptunnel $(BASEDIR)$(prefix)/sbin/ + +clean: + rm -f Makefile.depend $(OBJECTS) udptunnel + +%.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< + +udptunnel: $(OBJECTS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDADD) $(LIBS) + +depend: Makefile.depend +Makefile.depend: + $(CC) $(CPPFLAGS) $(CFLAGS) -MM -MG *.c > $@ + +-include Makefile.depend diff --git a/rooter/0optionalapps/udp-tunnel/src/log.c b/rooter/0optionalapps/udp-tunnel/src/log.c new file mode 100644 index 0000000..91bb04d --- /dev/null +++ b/rooter/0optionalapps/udp-tunnel/src/log.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2018 Marco d'Itri + * + * Inspired by log.c from the cowdancer package by James Clarke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "utils.h" + +static log_level filter_level = log_info; + +/* + * Return the appropriate file handle (stdout vs. stderr) for the log level. + */ +static FILE *file_for_level(log_level level) +{ + if (level & log_stderr || filter_level & log_stderr) + return stderr; + + if ((level & LOG_LEVEL_MASK) > log_warning) + return stdout; + else + return stderr; +} + +static void log_doit(log_level level, const char *format, va_list args) +{ + static int syslog_initialized; + + if ((level & LOG_LEVEL_MASK) > (filter_level & LOG_LEVEL_MASK)) + return; + + if (level & log_syslog || filter_level & log_syslog) { + if (!syslog_initialized) { + openlog(NULL, LOG_PID, LOG_DAEMON); + syslog_initialized = 1; + } + + if (level & log_strerror) { + int len = strlen(format); + char *format2; + + format2 = NOFAIL(malloc(len + 4 + 1)); + strcpy(format2, format); + strcpy(format2 + len, ": %m"); + vsyslog(level & LOG_LEVEL_MASK, format2, args); + free(format2); + } else { + vsyslog(level & LOG_LEVEL_MASK, format, args); + } + return; + } + + vfprintf(file_for_level(level), format, args); + if (level & log_strerror) + fprintf(file_for_level(level), ": %s", strerror(errno)); + fprintf(file_for_level(level), "\n"); +} + +log_level log_get_filter_level(void) +{ + return filter_level; +} + +void log_set_options(log_level filter_level_new) +{ + filter_level = filter_level_new; +} + +void log_printf(log_level level, const char *format, ...) +{ + va_list args; + + va_start(args, format); + log_doit(level, format, args); + va_end(args); +} + +void log_printf_exit(int status, log_level level, const char *format, ...) +{ + va_list args; + + va_start(args, format); + log_doit(level, format, args); + va_end(args); + + exit(status); +} + +void log_printf_err(log_level level, const char *format, ...) +{ + va_list args; + + va_start(args, format); + log_doit(level | log_strerror, format, args); + va_end(args); +} + +void log_printf_err_exit(int status, log_level level, const char *format, ...) +{ + va_list args; + + va_start(args, format); + log_doit(level | log_strerror, format, args); + va_end(args); + + exit(status); +} + diff --git a/rooter/0optionalapps/udp-tunnel/src/log.h b/rooter/0optionalapps/udp-tunnel/src/log.h new file mode 100644 index 0000000..e42665d --- /dev/null +++ b/rooter/0optionalapps/udp-tunnel/src/log.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 Marco d'Itri + * + * Inspired by log.c from the cowdancer package by James Clarke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __LOG_H__ +#define __LOG_H__ + +#include + +#include "utils.h" + +typedef enum log_level { + /* the value of the first 3 bits matches the syslog(3) levels */ + log_emerg = 0, + log_alert = 1, + log_crit = 2, + log_err = 3, + log_warning = 4, + log_notice = 5, + log_info = 6, + log_debug = 7, + log_nothing = 8, + + /* the following entries are bit flags to be OR'ed with the level */ + log_stderr = 0x10, + log_syslog = 0x20, + log_strerror = 0x40, +} log_level; + +/* remove the flags from log_level */ +#define LOG_LEVEL_MASK 0xf + +log_level log_get_filter_level(void); + +void log_set_options(log_level filter_level_new); + +__attribute__ ((format(printf, 2, 3))) +void log_printf(log_level level, const char *format, ...); + +__attribute__ ((format(printf, 3, 4), noreturn)) +void log_printf_exit(int status, log_level level, const char *format, ...); + +__attribute__ ((format(printf, 2, 3))) +void log_printf_err(log_level level, const char *format, ...); + +__attribute__ ((format(printf, 3, 4), noreturn)) +void log_printf_err_exit(int status, log_level level, const char *format, ...); + +#define err_sys(...) log_printf_err_exit(1, log_err, __VA_ARGS__) + +#endif /* !__LOG_H__ */ diff --git a/rooter/0optionalapps/udp-tunnel/src/network.c b/rooter/0optionalapps/udp-tunnel/src/network.c new file mode 100644 index 0000000..2c0f2c1 --- /dev/null +++ b/rooter/0optionalapps/udp-tunnel/src/network.c @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2018 Marco d'Itri + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* for getaddrinfo... */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "network.h" +#include "utils.h" +#include "log.h" + +char *print_addr_port(const struct sockaddr *addr, socklen_t addrlen) +{ + static char buf[1100], address[1025], port[32]; + int err; + + err = getnameinfo(addr, addrlen, address, sizeof(address), + port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); + if (err == EAI_SYSTEM) + err_sys("getnameinfo"); + else if (err) + log_printf_exit(1, log_err, "getnameinfo: %s", gai_strerror(err)); + + if (addr->sa_family == AF_INET6) + snprintf(buf, sizeof(buf) - 1, "[%s]:%s", address, port); + else + snprintf(buf, sizeof(buf) - 1, "%s:%s", address, port); + + return buf; +} + +static char *ai_print_addr_port(struct addrinfo *ai) +{ + return print_addr_port((struct sockaddr *) ai->ai_addr, ai->ai_addrlen); +} + +/* + * Try to parse anything that looks like: + * - an IPv4 or IPv6 address or a domain, with an optional port number + * - a port number + * + * address and/or port will be NULL if not found in the input. + * If address and port are not NULL then they must be freed by the caller. + */ +static void parse_address_port(const char *input, char **address, char **port) +{ + const char *p; + + *address = NULL; + *port = NULL; + + if (*input == '\0') { + return; + } else if (*input == '[' && (p = strchr(input, ']'))) { /* IPv6 */ + char *s; + int len = p - input - 1; + + *address = s = NOFAIL(malloc(len + 1)); + memcpy(s, input + 1, len); + *(s + len) = '\0'; + + p = strchr(p, ':'); + if (p && *(p + 1) != '\0') + *port = NOFAIL(strdup(p + 1)); /* IPv6 + port */ + } else if ((p = strchr(input, ':')) && /* IPv6, no port */ + strchr(p + 1, ':')) { /* and no brackets */ + *address = NOFAIL(strdup(input)); + } else if ((p = strchr(input, ':'))) { /* IPv4 + port */ + char *s; + int len = p - input; + + if (len) { + *address = s = NOFAIL(malloc(len + 1)); + memcpy(s, input, len); + *(s + len) = '\0'; + } + + p++; + if (*p != '\0') + *port = NOFAIL(strdup(p)); + } else { + for (p = input; *p; p++) + if (!isdigit(p[0])) + break; + if (*p) + *address = NOFAIL(strdup(input)); /* IPv4, no port */ + else + *port = NOFAIL(strdup(input)); /* just the port */ + } +} + +int udp_listener(const char *s) +{ + char *address, *port; + struct addrinfo hints, *res, *ai; + int err, fd; + + parse_address_port(s, &address, &port); + + if (!port) + log_printf_exit(2, log_err, "Missing port in '%s'!", s); + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE | AI_IDN; + + err = getaddrinfo(address, port, &hints, &res); + if (err == EAI_SYSTEM) + err_sys("getaddrinfo(%s:%s)", address, port); + else if (err) + log_printf_exit(1, log_err, "Cannot resolve %s:%s: %s", + address, port, gai_strerror(err)); + + if (address) + free(address); + if (port) + free(port); + + for (ai = res; ai; ai = ai->ai_next) { + if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) + continue; /* ignore */ + if (bind(fd, (struct sockaddr *) ai->ai_addr, ai->ai_addrlen) == 0) + break; /* success */ + close(fd); + } + + if (!ai) + err_sys("Cannot bind to %s", s); + + log_printf(log_info, "Listening for UDP connections on %s", + ai_print_addr_port(ai)); + + freeaddrinfo(res); + + return fd; +} + +int *tcp_listener(const char *s) +{ + char *address, *port; + struct addrinfo hints, *res, *ai; + int err, fd, opt; + int fd_num = 0; + int *fd_list = NULL; + size_t allocated_fds = 0; + + parse_address_port(s, &address, &port); + + if (!port) + log_printf_exit(2, log_err, "Missing port in '%s'!", s); + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE | AI_IDN; + + err = getaddrinfo(address, port, &hints, &res); + if (err == EAI_SYSTEM) + err_sys("getaddrinfo(%s:%s)", address, port); + else if (err) + log_printf_exit(1, log_err, "Cannot resolve %s:%s: %s", + address, port, gai_strerror(err)); + + if (address) + free(address); + if (port) + free(port); + + /* add to fd_list all the sockets which match ai_flags */ + for (ai = res; ai; ai = ai->ai_next) { + if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) + continue; /* ignore */ + opt = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) + err_sys("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); + if (bind(fd, (struct sockaddr *) ai->ai_addr, ai->ai_addrlen) < 0) + err_sys("Cannot bind to %s", s); + + /* success */ + if (listen(fd, 128) < 0) + err_sys("listen"); + + if (allocated_fds < fd_num + 1 + 1) { + allocated_fds += 8; + fd_list = realloc(fd_list, allocated_fds * sizeof(int)); + } + fd_list[fd_num++] = fd; + + log_printf(log_info, "Listening for TCP connections on %s", + ai_print_addr_port(ai)); + } + + /* and then add -1 as the list terminator */ + if (allocated_fds < fd_num + 1 + 1) + fd_list = realloc(fd_list, ++allocated_fds * sizeof(int)); + fd_list[fd_num] = -1; + + if (!fd_list) + err_sys("socket"); + + freeaddrinfo(res); + + return fd_list; +} + +/* + * Accept new connections and return after forking for each one. + */ +int accept_connections(int listening_sockets[]) +{ + while (1) { + int max = 0; + int i, fd; + fd_set readfds; + pid_t pid; + + FD_ZERO(&readfds); + for (i = 0; listening_sockets[i] != -1; i++) { + int flags; + + if ((flags = fcntl(listening_sockets[i], F_GETFL, 0)) < 0) + err_sys("fcntl(F_GETFL)"); + if (fcntl(listening_sockets[i], F_SETFL, flags | O_NONBLOCK) < 0) + err_sys("fcntl(F_SETFL, O_NONBLOCK)"); + + FD_SET(listening_sockets[i], &readfds); + SET_MAX(listening_sockets[i]); + } + + if (select(max, &readfds, NULL, NULL, NULL) < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + err_sys("select"); + } + + for (i = 0; listening_sockets[i] != -1; i++) { + int listen_sock; + struct sockaddr_storage client_addr; + socklen_t addrlen = sizeof(client_addr); + + if (!FD_ISSET(listening_sockets[i], &readfds)) + continue; + listen_sock = listening_sockets[i]; + + fd = accept(listen_sock, (struct sockaddr *) &client_addr, &addrlen); + if (fd < 0) { + if (errno == EAGAIN) + continue; + err_sys("accept"); + } + + log_printf(log_notice, "Received a TCP connection from %s", + print_addr_port((struct sockaddr *) &client_addr, addrlen)); + +#if 0 + /* do not fork, for testing */ + pid = 0; +#else + pid = fork(); +#endif + + if (pid < 0) + err_sys("fork"); + + if (pid > 0) { + close(fd); + } else { + for (i = 0; listening_sockets[i] != -1; i++) + close(listening_sockets[i]); + return fd; + } + } + } +} + +int udp_client(const char *s, struct sockaddr_storage *remote_udpaddr) +{ + char *address, *port; + struct addrinfo hints, *res, *ai; + int err, fd; + + parse_address_port(s, &address, &port); + + if (!address || !port) + log_printf_exit(2, log_err, "Missing address or port in '%s'!", s); + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_ADDRCONFIG | AI_IDN; + + err = getaddrinfo(address, port, &hints, &res); + if (err == EAI_SYSTEM) + err_sys("getaddrinfo(%s:%s)", address, port); + else if (err) + log_printf_exit(1, log_err, "Cannot resolve %s:%s: %s", + address, port, gai_strerror(err)); + + if (address) + free(address); + if (port) + free(port); + + /* continue with the first socket which matches ai_flags */ + for (ai = res; ai; ai = ai->ai_next) { + if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) + continue; /* ignore */ + break; /* success */ + } + + if (!ai) + err_sys("socket"); + + log_printf(log_debug, "The UDP destination is %s", ai_print_addr_port(ai)); + + /* + * Return to the caller the resolved address, to be able to use it as the + * destination address of the next UDP packet. + */ + if (remote_udpaddr) + memcpy(remote_udpaddr, ai->ai_addr, ai->ai_addrlen); + + freeaddrinfo(res); + + return fd; +} + +int tcp_client(const char *s) +{ + char *address, *port; + struct addrinfo hints, *res, *ai; + int err, fd; + + parse_address_port(s, &address, &port); + + if (!address || !port) + log_printf_exit(2, log_err, "Missing address or port in '%s'!", s); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG | AI_IDN; + + err = getaddrinfo(address, port, &hints, &res); + if (err == EAI_SYSTEM) + err_sys("getaddrinfo(%s:%s)", address, port); + else if (err) + log_printf_exit(1, log_err, "Cannot resolve %s:%s: %s", + address, port, gai_strerror(err)); + + if (address) + free(address); + if (port) + free(port); + + for (ai = res; ai; ai = ai->ai_next) { + if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) + continue; /* ignore */ + if (connect(fd, (struct sockaddr *) ai->ai_addr, ai->ai_addrlen) == 0) + break; /* success */ + close(fd); + } + + if (!ai) + err_sys("Cannot connect to %s", s); + + log_printf(log_info, "TCP connection opened to %s", + ai_print_addr_port(ai)); + + freeaddrinfo(res); + + return fd; +} + diff --git a/rooter/0optionalapps/udp-tunnel/src/network.h b/rooter/0optionalapps/udp-tunnel/src/network.h new file mode 100644 index 0000000..2fafdc1 --- /dev/null +++ b/rooter/0optionalapps/udp-tunnel/src/network.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 Marco d'Itri + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __NETWORK_H__ +#define __NETWORK_H__ + +#define SET_MAX(fd) do { if (max < (fd) + 1) { max = (fd) + 1; } } while (0) + +char *print_addr_port(const struct sockaddr *addr, socklen_t addrlen); + +int udp_listener(const char *s); + +int *tcp_listener(const char *s); + +int udp_listener_sa(const int num); + +int *tcp_listener_sa(const int num); + +int udp_client(const char *s, struct sockaddr_storage *remote_udpaddr); + +int tcp_client(const char *s); + +int accept_connections(int listening_sockets[]); + +#endif diff --git a/rooter/0optionalapps/udp-tunnel/src/udptunnel.c b/rooter/0optionalapps/udp-tunnel/src/udptunnel.c new file mode 100644 index 0000000..8dd9c17 --- /dev/null +++ b/rooter/0optionalapps/udp-tunnel/src/udptunnel.c @@ -0,0 +1,523 @@ +/* + * Copyright (C) 2018 Marco d'Itri + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * + * Parts of this program are derived from udptunnel.c by Jonathan Lennox. + * This is the license of the original code: + * + * Copyright 1999, 2001 by Columbia University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS + * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* for sigaction... */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYSTEMD_SD_DAEMON_H +#include +#endif + +#include "utils.h" +#include "log.h" +#include "network.h" + +#ifdef HAVE_GETOPT_LONG +#include +#endif + +#define TCPBUFFERSIZE 65536 +#define UDPBUFFERSIZE (TCPBUFFERSIZE - 2) /* TCP packet - length */ + +struct out_packet { + uint16_t length; + char buf[UDPBUFFERSIZE]; +}; + +struct opts { + const char *udpaddr, *tcpaddr; + + int is_server; + int use_inetd; + char *handshake; + int timeout; +}; + +struct relay { + struct sockaddr_storage remote_udpaddr; + + int udp_sock, tcp_sock; + + int expect_handshake; + char handshake[32]; + int udp_timeout, tcp_timeout; + char buf[TCPBUFFERSIZE]; + char *buf_ptr, *packet_start; + int packet_length; + enum { + uninitialized = 0, + reading_handshake, + reading_length, + reading_packet, + } state; +}; + +static void usage(int status) +{ + FILE *fp = status == 0 ? stdout : stderr; + + fprintf(fp, "Usage: udptunnel [OPTION]... [[SOURCE:]PORT] DESTINATION:PORT\n\n"); + fprintf(fp, "-s --server listen for TCP connections\n"); + fprintf(fp, "-i --inetd expect to be started by inetd\n"); + fprintf(fp, "-T N --timeout N close the source connection after N seconds\n"); + fprintf(fp, " where no data was received\n"); + fprintf(fp, "-S --syslog log to syslog instead of standard error\n"); + fprintf(fp, "-v --verbose explain what is being done\n"); + fprintf(fp, "-h --help display this help and exit\n"); + fprintf(fp, "\nSOURCE:PORT must not be specified when using inetd or socket activation.\n\n"); + fprintf(fp, "If the -s option is used then the program will listen on SOURCE:PORT for TCP\n"); + fprintf(fp, "connections and relay the encapsulated packets with UDP to DESTINATION:PORT.\n"); + fprintf(fp, "Otherwise it will listen on SOURCE:PORT for UDP packets and encapsulate\n"); + fprintf(fp, "them in a TCP connection to DESTINATION:PORT.\n"); + + exit(status); +} + +static void parse_args(int argc, char *argv[], struct opts *opts) +{ +#ifdef HAVE_GETOPT_LONG + const struct option longopts[] = { + {"inetd", no_argument, NULL, 'i' }, + {"server", no_argument, NULL, 's' }, + {"syslog", no_argument, NULL, 'S' }, + {"timeout", required_argument, NULL, 'T' }, + {"help", no_argument, NULL, 'h' }, + {"verbose", no_argument, NULL, 'v' }, + {NULL, 0, NULL, 0 }, + }; + int longindex; +#endif + int c; + int expected_args; + int verbose = 0; + int use_syslog = 0; + + /* defaults */ + opts->handshake = NOFAIL(malloc(32)); + memcpy(opts->handshake, "udptunnel by md.\0\0\0\x01\x03\x06\x10\x15\x21\x28\x36\x45\x55\x66\x78\x91", 32); + + while ((c = GETOPT_LONGISH(argc, argv, "ihsvST:", + longopts, &longindex)) > 0) { + switch (c) { + case 'i': + opts->use_inetd = 1; + break; + case 's': + opts->is_server = 1; + break; + case 'S': + use_syslog = 1; + break; + case 'T': + opts->timeout = atol(optarg); + break; + case 'v': + verbose++; + break; + case 'h': + usage(0); + break; + default: + usage(2); + break; + } + } + + /* + * Look for 2 command line arguments (source and destination) + * if used in standalone mode or only 1 argument (destination) + * if used in inetd or socket activated modes. + */ + expected_args = (sd_listen_fds(0) || opts->use_inetd) ? 1 : 2; + + if (argc - optind == 0) + usage(2); + if (argc - optind != expected_args) { + fprintf(stderr, "Expected %d argument(s)!\n\n", expected_args); + usage(2); + } + + /* the source and destination addresses */ + if (opts->is_server) { + if (expected_args == 2) + opts->tcpaddr = NOFAIL(strdup(argv[optind++])); + opts->udpaddr = NOFAIL(strdup(argv[optind++])); + } else { + if (expected_args == 2) + opts->udpaddr = NOFAIL(strdup(argv[optind++])); + opts->tcpaddr = NOFAIL(strdup(argv[optind++])); + } + + if (!verbose) + log_set_options(log_warning); + else if (verbose == 1) + log_set_options(log_notice); + else if (verbose == 2) + log_set_options(log_info); + else + log_set_options(log_debug); + + if (use_syslog) + log_set_options(log_get_filter_level() | log_syslog); +} + +int udp_listener_sa(const int num) +{ + int fd = SD_LISTEN_FDS_START; + + if (num != 1) + log_printf_exit(2, log_err, + "UDP socket activation supports a single socket."); + + if (sd_is_socket(fd, AF_UNSPEC, SOCK_DGRAM, -1) <= 0) + log_printf_exit(2, log_err, + "UDP socket activation fd %d is not valid.", fd); + + return fd; +} + +int *tcp_listener_sa(const int num) +{ + int fd; + int *fds; + int fd_num = 0; + + fds = NOFAIL(malloc((num + 1) * sizeof(int))); + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + num; fd++) { + if (sd_is_socket(fd, AF_UNSPEC, SOCK_STREAM, 1) <= 0) + log_printf_exit(2, log_err, + "TCP socket activation fd %d is not valid.", fd); + fds[fd_num++] = fd; + } + + fds[fd_num] = -1; + + return fds; +} + +static void udp_to_tcp(struct relay *relay) +{ + struct out_packet p; + int buflen; + struct sockaddr_storage remote_udpaddr; + socklen_t addrlen = sizeof(remote_udpaddr); + + buflen = recvfrom(relay->udp_sock, p.buf, UDPBUFFERSIZE, 0, + (struct sockaddr *) &remote_udpaddr, &addrlen); + if (buflen < 0) + err_sys("recvfrom(udp)"); + if (buflen == 0) + return; /* ignore empty packets */ + + /* + * Store the source address of the received UDP packet, to be able to use + * it in send_udp_packet as the destination address of the next UDP reply. + */ + memcpy(&(relay->remote_udpaddr), &remote_udpaddr, addrlen); + +#ifdef DEBUG + log_printf(log_debug, "Received a %d bytes UDP packet from %s", buflen, + print_addr_port((struct sockaddr *) &remote_udpaddr, addrlen)); +#endif + + p.length = htons(buflen); + if (send(relay->tcp_sock, &p, buflen + sizeof(p.length), 0) < 0) + err_sys("send(tcp)"); +} + +static void send_udp_packet(struct relay *relay) +{ + int opt = 0; + socklen_t len = sizeof(opt); + + if (relay->remote_udpaddr.ss_family == 0) { + log_printf(log_info, + "Ignoring a packet for a still unknown UDP destination!"); + return; + } + + if (sendto(relay->udp_sock, relay->packet_start, relay->packet_length, 0, + (struct sockaddr *) &relay->remote_udpaddr, + sizeof(relay->remote_udpaddr)) >= 0) + return; + + /* this is the error path */ + if (errno != ECONNREFUSED) + err_sys("sendto(udp)"); + + /* clear the error if there is no UDP listener yet on the other end */ + log_printf(log_info, "sendto(udp) returned ECONNREFUSED: ignored"); + if (getsockopt(relay->udp_sock, SOL_SOCKET, SO_ERROR, &opt, &len) < 0) + err_sys("getsockopt(udp, SOL_SOCKET, SO_ERROR)"); + + return; +} + +static void tcp_to_udp(struct relay *relay) +{ + int read_len; + + if (relay->state == uninitialized) { + if (relay->expect_handshake) { + relay->state = reading_handshake; + relay->packet_length = sizeof(relay->handshake); + } else { + relay->state = reading_length; + relay->packet_length = sizeof(uint16_t); + } + relay->buf_ptr = relay->buf; + relay->packet_start = relay->buf; + } + + read_len = read(relay->tcp_sock, relay->buf_ptr, + (relay->buf + TCPBUFFERSIZE - relay->buf_ptr)); + if (read_len < 0) + err_sys("read(tcp)"); + + if (read_len == 0) + log_printf_exit(0, log_notice, "Remote closed the connection"); + + relay->buf_ptr += read_len; + + while (relay->buf_ptr - relay->packet_start >= relay->packet_length) { + if (relay->state == reading_handshake) { + /* check the handshake string */ + if (memcmp(relay->packet_start, &(relay->handshake), + sizeof(relay->handshake)) != 0) + log_printf_exit(0, log_info, + "Received a bad handshake, exiting"); + log_printf(log_debug, "Received a good handshake"); + relay->packet_start += sizeof(relay->handshake); + relay->state = reading_length; + relay->packet_length = sizeof(uint16_t); + } else if (relay->state == reading_length) { + /* read the lenght of the next packet */ + relay->packet_length = ntohs(*(uint16_t *) relay->packet_start); + relay->packet_start += sizeof(uint16_t); + relay->state = reading_packet; + } else if (relay->state == reading_packet) { + /* read an encapsulated packet and send it as UDP */ +#ifdef DEBUG + log_printf(log_debug, "Received a %u bytes TCP packet", + relay->packet_length); +#endif + + send_udp_packet(relay); + + memmove(relay->buf, relay->packet_start + relay->packet_length, + relay->buf_ptr - + (relay->packet_start + relay->packet_length)); + relay->buf_ptr -= + relay->packet_length + (relay->packet_start - relay->buf); + relay->packet_start = relay->buf; + relay->state = reading_length; + relay->packet_length = sizeof(uint16_t); + } + } +} + +static void send_handshake(struct relay *relay) +{ + if (sendto(relay->tcp_sock, relay->handshake, sizeof(relay->handshake), 0, + (struct sockaddr *) &relay->remote_udpaddr, + sizeof(relay->remote_udpaddr)) < 0) + err_sys("sendto(tcp, handshake)"); +} + +static void wait_for_child(int sig) +{ + while (waitpid(-1, NULL, WNOHANG) > 0); +} + +static void main_loop(struct relay *relay) +{ + time_t last_udp_input, last_tcp_input; + + last_udp_input = relay->udp_timeout ? time(NULL) : 0; + last_tcp_input = relay->tcp_timeout ? time(NULL) : 0; + + while (1) { + int ready_fds; + int max = 0; + fd_set readfds; + struct timeval tv, *ptv; + + FD_ZERO(&readfds); + FD_SET(relay->tcp_sock, &readfds); + SET_MAX(relay->tcp_sock); + FD_SET(relay->udp_sock, &readfds); + SET_MAX(relay->udp_sock); + + /* + * If a data timeout was configured then set a 10s timeout for + * select. + */ + if (last_udp_input || last_tcp_input) { + tv.tv_usec = 0; + tv.tv_sec = 10; + ptv = &tv; + } else { + ptv = NULL; + } + + ready_fds = select(max, &readfds, NULL, NULL, ptv); + if (ready_fds < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + err_sys("select"); + } + + /* check the timeout if one was configured and select(2) timed out */ + if (last_udp_input && !ready_fds) { /* timeout */ + if (time(NULL) - last_udp_input > relay->udp_timeout) + log_printf_exit(0, log_notice, + "Exiting after a %ds timeout for UDP input", + relay->udp_timeout); + } + if (last_tcp_input && !ready_fds) { /* timeout */ + if (time(NULL) - last_tcp_input > relay->tcp_timeout) + log_printf_exit(0, log_notice, + "Exiting after a %ds timeout for TCP input", + relay->tcp_timeout); + } + + if (FD_ISSET(relay->tcp_sock, &readfds)) { + tcp_to_udp(relay); + if (last_tcp_input) + last_tcp_input = time(NULL); + } + if (FD_ISSET(relay->udp_sock, &readfds)) { + udp_to_tcp(relay); + if (last_udp_input) + last_udp_input = time(NULL); + } + } +} + +int main(int argc, char *argv[]) +{ + struct opts opts; + struct relay relay; + + memset(&relay, 0, sizeof(relay)); + relay.tcp_sock = -1; + + memset(&opts, 0, sizeof(opts)); + parse_args(argc, argv, &opts); + if (opts.handshake) + memcpy(relay.handshake, opts.handshake, sizeof(relay.handshake)); + + sd_notify(0, "READY=1"); + + if (opts.is_server) { + struct sigaction sa; + + sa.sa_handler = wait_for_child; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if (sigaction(SIGCHLD, &sa, NULL) == -1) + err_sys("sigaction"); + + if (opts.timeout) + relay.tcp_timeout = opts.timeout; + relay.expect_handshake = 1; + + if (opts.use_inetd) { + relay.tcp_sock = 0; + log_set_options(log_get_filter_level() | log_syslog); + } else { + int socket_activation_fds = sd_listen_fds(0); + int *listening_sockets; + + if (socket_activation_fds) + listening_sockets = tcp_listener_sa(socket_activation_fds); + else + listening_sockets = tcp_listener(opts.tcpaddr); + relay.tcp_sock = accept_connections(listening_sockets); + } + relay.udp_sock = udp_client(opts.udpaddr, &relay.remote_udpaddr); + } else { + if (opts.timeout) + relay.udp_timeout = opts.timeout; + + if (opts.use_inetd) { + relay.udp_sock = 0; + log_set_options(log_get_filter_level() | log_syslog); + } else { + int socket_activation_fds = sd_listen_fds(0); + + if (socket_activation_fds) + relay.udp_sock = udp_listener_sa(socket_activation_fds); + else + relay.udp_sock = udp_listener(opts.udpaddr); + } + relay.tcp_sock = tcp_client(opts.tcpaddr); + + send_handshake(&relay); + } + + main_loop(&relay); + exit(0); +} + diff --git a/rooter/0optionalapps/udp-tunnel/src/utils.c b/rooter/0optionalapps/udp-tunnel/src/utils.c new file mode 100644 index 0000000..088ffe8 --- /dev/null +++ b/rooter/0optionalapps/udp-tunnel/src/utils.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 Marco d'Itri + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "utils.h" + +void *do_nofail(void *ptr, const char *file, const int line) +{ + if (ptr) + return ptr; + + fprintf(stderr, "Memory allocation failure at %s:%d.", file, line); + exit(1); +} + diff --git a/rooter/0optionalapps/udp-tunnel/src/utils.h b/rooter/0optionalapps/udp-tunnel/src/utils.h new file mode 100644 index 0000000..be91197 --- /dev/null +++ b/rooter/0optionalapps/udp-tunnel/src/utils.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 Marco d'Itri + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __UTILS_H__ +#define __UTILS_H__ + +#if !defined __GNUC__ && !defined __attribute__ +#define __attribute__(x) /*NOTHING*/ +#endif + +#ifndef AI_IDN +#define AI_IDN 0 +#endif + +#ifndef AI_ADDRCONFIG +#define AI_ADDRCONFIG 0 +#endif + +#ifndef SD_LISTEN_FDS_START +#define SD_LISTEN_FDS_START 0 +#define sd_listen_fds(a) 0 +#define sd_notify(a, b) +#define sd_is_socket(a, b, c, d) -1 +#endif + +#if defined __GLIBC__ || (defined __APPLE__ && defined __MACH__) +#define HAVE_GETOPT_LONG +#endif + +#ifdef HAVE_GETOPT_LONG +#define GETOPT_LONGISH(c, v, o, l, i) getopt_long(c, v, o, l, i) +#else +#define GETOPT_LONGISH(c, v, o, l, i) getopt(c, v, o) +#endif + +#define NOFAIL(ptr) do_nofail((ptr), __FILE__, __LINE__) + +void *do_nofail(void *ptr, const char *file, const int line); + +#endif diff --git a/rooter/0optionalapps/webconsole/Makefile b/rooter/0optionalapps/webconsole/Makefile new file mode 100644 index 0000000..eb8cc4b --- /dev/null +++ b/rooter/0optionalapps/webconsole/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=webconsole +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/webconsole + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Optional Applications + TITLE:=Install scripts for Web Console + PKGARCH:=all +endef + +define Package/webconsole/description + Helper scripts to install scripts for Web Console +endef + + +define Build/Compile +endef + +define Package/webconsole/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,webconsole)) diff --git a/rooter/0optionalapps/webconsole/files/usr/lib/lua/luci/controller/webconsole.lua b/rooter/0optionalapps/webconsole/files/usr/lib/lua/luci/controller/webconsole.lua new file mode 100644 index 0000000..d65745a --- /dev/null +++ b/rooter/0optionalapps/webconsole/files/usr/lib/lua/luci/controller/webconsole.lua @@ -0,0 +1,31 @@ +-- A simple web console in case you don't have access to the shell +-- +-- Hua Shao + +module("luci.controller.webconsole", package.seeall) +local http = require("luci.http") + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" + local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + if (multilock == "0") or (multilock == "1" and rootlock == "1") then + entry({"admin", "system", "console"}, template("web/web_console"), _(translate("Web Console")), 66) + end + entry({"admin", "system", "webcmd"}, call("action_webcmd")) +end + +function action_webcmd() + local cmd = http.formvalue("cmd") + if cmd then + local fp = io.popen(tostring(cmd).." 2>&1") + local result = fp:read("*a") + fp:close() + result = result:gsub("<", "<") + http.write(tostring(result)) + else + http.write_json(http.formvalue()) + end +end diff --git a/rooter/0optionalapps/webconsole/files/usr/lib/lua/luci/view/web/web_console.htm b/rooter/0optionalapps/webconsole/files/usr/lib/lua/luci/view/web/web_console.htm new file mode 100644 index 0000000..682dcad --- /dev/null +++ b/rooter/0optionalapps/webconsole/files/usr/lib/lua/luci/view/web/web_console.htm @@ -0,0 +1,51 @@ +<%+header%> + +

                          <%:Web Console%>

                          +
                          +
                          + <%:Execute shell commands or scripts as root.%><%:Be Careful%>. +

                          <%:Press%> Enter <%:to execute. Press%> Shift+Enter <%:to start a new line.%>

                          +

                          +

                          + + + + + + + +

                          
                          +    
                          +
                          + + + +<%+footer%> + diff --git a/rooter/0protocols/luci-proto-3x/Makefile b/rooter/0protocols/luci-proto-3x/Makefile new file mode 100644 index 0000000..ee45aba --- /dev/null +++ b/rooter/0protocols/luci-proto-3x/Makefile @@ -0,0 +1,53 @@ +# +# Copyright (C) 2007-2013 OpenWrt.org +# Copyright (C) 2010 Vertical Communications +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-proto-3x +PKG_VERSION:=1.0 +PKG_RELEASE:=1 +PKG_MAINTAINER:=Dairyman +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)-$(PKG_RELEASE) + +include $(INCLUDE_DIR)/package.mk + +define Package/luci-proto-3x/Default + VERSION:=$(PKG_VERSION)-$(PKG_RELEASE) + URL:=http://openwrt.org/ + MAINTAINER:=Dairyman +endef + +define Package/luci-proto-3x +$(call Package/luci-proto-3x/Default) + SECTION:=net + CATEGORY:=ROOter + SUBMENU:=Protocols + TITLE:=Support for 3x +endef + +define Package/luci-proto-3x/description + This package contains LuCI support for 3x +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile/Default +endef + +Build/Compile = $(Build/Compile/Default) + +define Package/luci-proto-3x/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,luci-proto-3x)) diff --git a/rooter/0protocols/luci-proto-3x/files/usr/lib/lua/luci/model/cbi/admin_network/proto_3x.lua b/rooter/0protocols/luci-proto-3x/files/usr/lib/lua/luci/model/cbi/admin_network/proto_3x.lua new file mode 100644 index 0000000..59bf2f6 --- /dev/null +++ b/rooter/0protocols/luci-proto-3x/files/usr/lib/lua/luci/model/cbi/admin_network/proto_3x.lua @@ -0,0 +1,146 @@ +-- Copyright 2011 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +local map, section, net = ... + +local device, apn, service, pincode, username, password, dialnumber +local ipv6, maxwait, defaultroute, metric, peerdns, dns, + keepalive_failure, keepalive_interval, demand + + +device = section:taboption("general", Value, "device", translate("Modem device")) +device.rmempty = false + +local device_suggestions = nixio.fs.glob("/dev/tty[A-Z]*") + or nixio.fs.glob("/dev/tts/*") + +if device_suggestions then + local node + for node in device_suggestions do + device:value(node) + end +end + + +service = section:taboption("general", Value, "service", translate("Service Type")) +service:value("", translate("-- Please choose --")) +service:value("umts", "UMTS/GPRS") +service:value("umts_only", translate("UMTS only")) +service:value("gprs_only", translate("GPRS only")) +service:value("evdo", "CDMA/EV-DO") + + +apn = section:taboption("general", Value, "apn", translate("APN")) + + +pincode = section:taboption("general", Value, "pincode", translate("PIN")) + + +username = section:taboption("general", Value, "username", translate("PAP/CHAP username")) + + +password = section:taboption("general", Value, "password", translate("PAP/CHAP password")) +password.password = true + +dialnumber = section:taboption("general", Value, "dialnumber", translate("Dial number")) +dialnumber.placeholder = "*99***1#" + +if luci.model.network:has_ipv6() then + + ipv6 = section:taboption("advanced", Flag, "ipv6", + translate("Enable IPv6 negotiation on the PPP link")) + + ipv6.default = ipv6.disabled + +end + + +maxwait = section:taboption("advanced", Value, "maxwait", + translate("Modem init timeout"), + translate("Maximum amount of seconds to wait for the modem to become ready")) + +maxwait.placeholder = "20" +maxwait.datatype = "min(1)" + + +defaultroute = section:taboption("advanced", Flag, "defaultroute", + translate("Use default gateway"), + translate("If unchecked, no default route is configured")) + +defaultroute.default = defaultroute.enabled + + +metric = section:taboption("advanced", Value, "metric", + translate("Use gateway metric")) + +metric.placeholder = "0" +metric.datatype = "uinteger" +metric:depends("defaultroute", defaultroute.enabled) + + +peerdns = section:taboption("advanced", Flag, "peerdns", + translate("Use DNS servers advertised by peer"), + translate("If unchecked, the advertised DNS server addresses are ignored")) + +peerdns.default = peerdns.enabled + + +dns = section:taboption("advanced", DynamicList, "dns", + translate("Use custom DNS servers")) + +dns:depends("peerdns", "") +dns.datatype = "ipaddr" +dns.cast = "string" + + +keepalive_failure = section:taboption("advanced", Value, "_keepalive_failure", + translate("LCP echo failure threshold"), + translate("Presume peer to be dead after given amount of LCP echo failures, use 0 to ignore failures")) + +function keepalive_failure.cfgvalue(self, section) + local v = m:get(section, "keepalive") + if v and #v > 0 then + return tonumber(v:match("^(%d+)[ ,]+%d+") or v) + end +end + +function keepalive_failure.write() end +function keepalive_failure.remove() end + +keepalive_failure.placeholder = "0" +keepalive_failure.datatype = "uinteger" + + +keepalive_interval = section:taboption("advanced", Value, "_keepalive_interval", + translate("LCP echo interval"), + translate("Send LCP echo requests at the given interval in seconds, only effective in conjunction with failure threshold")) + +function keepalive_interval.cfgvalue(self, section) + local v = m:get(section, "keepalive") + if v and #v > 0 then + return tonumber(v:match("^%d+[ ,]+(%d+)")) + end +end + +function keepalive_interval.write(self, section, value) + local f = tonumber(keepalive_failure:formvalue(section)) or 0 + local i = tonumber(value) or 5 + if i < 1 then i = 1 end + if f > 0 then + m:set(section, "keepalive", "%d %d" %{ f, i }) + else + m:del(section, "keepalive") + end +end + +keepalive_interval.remove = keepalive_interval.write +keepalive_interval.placeholder = "5" +keepalive_interval.datatype = "min(1)" + + +demand = section:taboption("advanced", Value, "demand", + translate("Inactivity timeout"), + translate("Close inactive connection after the given amount of seconds, use 0 to persist connection")) + +demand.placeholder = "0" +demand.datatype = "uinteger" diff --git a/rooter/0protocols/luci-proto-3x/files/usr/lib/lua/luci/model/network/proto_3x.lua b/rooter/0protocols/luci-proto-3x/files/usr/lib/lua/luci/model/network/proto_3x.lua new file mode 100644 index 0000000..e2ff6b9 --- /dev/null +++ b/rooter/0protocols/luci-proto-3x/files/usr/lib/lua/luci/model/network/proto_3x.lua @@ -0,0 +1,49 @@ +-- Copyright 2018 Florian Eckert +-- Licensed to the public under the Apache License 2.0. + +local netmod = luci.model.network +local interface = luci.model.network.interface + +local proto = netmod:register_protocol("3x") + +function proto.get_i18n(self) + return luci.i18n.translate("UMTS/GPRS/EV-DO") +end + +function proto.ifname(self) + return "3x-" .. self.sid +end + +function proto.get_interface(self) + return interface(self:ifname(), self) +end + +function proto.is_installed(self) + return nixio.fs.access("/lib/netifd/proto/3x.sh") +end + +function proto.opkg_package(self) + return "comgt" +end + +function proto.is_floating(self) + return true +end + +function proto.is_virtual(self) + return true +end + +function proto.get_interfaces(self) + return nil +end + +function proto.contains_interface(self, ifc) + if self:is_floating() then + return (netmod:ifnameof(ifc) == self:ifname()) + else + return netmod.protocol.contains_interface(self, ifc) + end +end + +netmod:register_pattern_virtual("^3x%-%w") diff --git a/rooter/0protocols/luci-proto-3x/files/www/luci-static/resources/protocol/3x.js b/rooter/0protocols/luci-proto-3x/files/www/luci-static/resources/protocol/3x.js new file mode 100644 index 0000000..a1c213b --- /dev/null +++ b/rooter/0protocols/luci-proto-3x/files/www/luci-static/resources/protocol/3x.js @@ -0,0 +1,11 @@ +'use strict';'require rpc';'require uci';'require form';'require network';var callFileList=rpc.declare({object:'file',method:'list',params:['path'],expect:{entries:[]},filter:function(list,params){var rv=[];for(var i=0;i0) +uci.set('network',section_id,'keepalive','%d %d'.format(f,i));else +uci.unset('network',section_id,'keepalive');} +return network.registerProtocol('3x',{getI18n:function(){return _('UMTS/GPRS/EV-DO');},getIfname:function(){return this._ubus('l3_device')||'3x-%s'.format(this.sid);},getOpkgPackage:function(){return'comgt';},isFloating:function(){return true;},isVirtual:function(){return true;},getDevices:function(){return null;},containsDevice:function(ifname){return(network.getIfnameOf(ifname)==this.getIfname());},renderFormOptions:function(s){var o;o=s.taboption('general',form.Value,'device',_('Modem device'));o.rmempty=false;o.load=function(section_id){return callFileList('/dev/').then(L.bind(function(devices){for(var i=0;i +-- Licensed to the public under the Apache License 2.0. + +local map, section, net = ... + +local device, apn, pincode, username, password +local auth, ipv6 + + +device = section:taboption("general", Value, "device", translate("Modem device")) +device.rmempty = false + +local device_suggestions = nixio.fs.glob("/dev/cdc-wdm*") + +if device_suggestions then + local node + for node in device_suggestions do + device:value(node) + end +end + + +apn = section:taboption("general", Value, "apn", translate("APN")) + + +pincode = section:taboption("general", Value, "pincode", translate("PIN")) + + +username = section:taboption("general", Value, "username", translate("PAP/CHAP username")) + + +password = section:taboption("general", Value, "password", translate("PAP/CHAP password")) +password.password = true + +auth = section:taboption("general", Value, "auth", translate("Authentication Type")) +auth:value("", translate("-- Please choose --")) +auth:value("both", "PAP/CHAP (both)") +auth:value("pap", "PAP") +auth:value("chap", "CHAP") +auth:value("none", "NONE") + +if luci.model.network:has_ipv6() then + ipv6 = section:taboption("advanced", Flag, "ipv6", translate("Enable IPv6 negotiation")) + ipv6.default = ipv6.disabled +end \ No newline at end of file diff --git a/rooter/0protocols/luci-proto-mbim/files/usr/lib/lua/luci/model/network/proto_mbim.lua b/rooter/0protocols/luci-proto-mbim/files/usr/lib/lua/luci/model/network/proto_mbim.lua new file mode 100644 index 0000000..3007480 --- /dev/null +++ b/rooter/0protocols/luci-proto-mbim/files/usr/lib/lua/luci/model/network/proto_mbim.lua @@ -0,0 +1,55 @@ +-- Copyright 2016 David Thornley +-- Licensed to the public under the Apache License 2.0. + +local netmod = luci.model.network +local interface = luci.model.network.interface +local proto = netmod:register_protocol("mbim") + +function proto.get_i18n(self) + return luci.i18n.translate("MBIM Cellular") +end + +function proto.ifname(self) + local base = netmod._M.protocol + local ifname = base.ifname(self) -- call base class "protocol.ifname(self)" + + -- Note: ifname might be nil if the adapter could not be determined through ubus (default name to mbim-wan in this case) + if ifname == nil then + ifname = "mbim-" .. self.sid + end + return ifname +end + +function proto.get_interface(self) + return interface(self:ifname(), self) +end + +function proto.opkg_package(self) + return "rmbim" +end + +function proto.is_installed(self) + return nixio.fs.access("/lib/netifd/proto/mbim.sh") +end + +function proto.is_floating(self) + return true +end + +function proto.is_virtual(self) + return true +end + +function proto.get_interfaces(self) + return nil +end + +function proto.contains_interface(self, ifc) + return (netmod:ifnameof(ifc) == self:ifname()) +end + +netmod:register_pattern_virtual("^mbim%-%w") + +netmod:register_error_code("CALL_FAILED", luci.i18n.translate("Call failed")) +netmod:register_error_code("NO_CID", luci.i18n.translate("Unable to obtain client ID")) +netmod:register_error_code("PLMN_FAILED", luci.i18n.translate("Setting PLMN failed")) diff --git a/rooter/0protocols/luci-proto-mbim/files/www/luci-static/resources/protocol/mbim.js b/rooter/0protocols/luci-proto-mbim/files/www/luci-static/resources/protocol/mbim.js new file mode 100644 index 0000000..337cdd3 --- /dev/null +++ b/rooter/0protocols/luci-proto-mbim/files/www/luci-static/resources/protocol/mbim.js @@ -0,0 +1,107 @@ +'use strict'; +'require rpc'; +'require form'; +'require network'; + +var callFileList = rpc.declare({ + object: 'file', + method: 'list', + params: [ 'path' ], + expect: { entries: [] }, + filter: function(list, params) { + var rv = []; + for (var i = 0; i < list.length; i++) + if (list[i].name.match(/^cdc-wdm/)) + rv.push(params.path + list[i].name); + return rv.sort(); + } +}); + +network.registerPatternVirtual(/^mbim-.+$/); +network.registerErrorCode('CALL_FAILED', _('Call failed')); +network.registerErrorCode('NO_CID', _('Unable to obtain client ID')); +network.registerErrorCode('PLMN_FAILED', _('Setting PLMN failed')); + +return network.registerProtocol('mbim', { + getI18n: function() { + return _('MBIM Cellular'); + }, + + getIfname: function() { + return this._ubus('l3_device') || 'mbim-%s'.format(this.sid); + }, + + getOpkgPackage: function() { + return 'rmbim'; + }, + + isFloating: function() { + return true; + }, + + isVirtual: function() { + return true; + }, + + getDevices: function() { + return null; + }, + + containsDevice: function(ifname) { + return (network.getIfnameOf(ifname) == this.getIfname()); + }, + + renderFormOptions: function(s) { + var dev = this.getL3Device() || this.getDevice(), o; + + o = s.taboption('general', form.Value, 'device', _('Modem device')); + o.rmempty = false; + o.load = function(section_id) { + return callFileList('/dev/').then(L.bind(function(devices) { + for (var i = 0; i < devices.length; i++) + this.value(devices[i]); + return form.Value.prototype.load.apply(this, [section_id]); + }, this)); + }; + + s.taboption('general', form.Value, 'apn', _('APN')); + s.taboption('general', form.Value, 'pincode', _('PIN')); + + o = s.taboption('general', form.ListValue, 'auth', _('Authentication Type')); + o.value('both', 'PAP/CHAP'); + o.value('pap', 'PAP'); + o.value('chap', 'CHAP'); + o.value('none', 'NONE'); + o.default = 'none'; + + o = s.taboption('general', form.Value, 'username', _('PAP/CHAP username')); + o.depends('auth', 'pap'); + o.depends('auth', 'chap'); + o.depends('auth', 'both'); + + o = s.taboption('general', form.Value, 'password', _('PAP/CHAP password')); + o.depends('auth', 'pap'); + o.depends('auth', 'chap'); + o.depends('auth', 'both'); + o.password = true; + + if (L.hasSystemFeature('ipv6')) { + o = s.taboption('advanced', form.Flag, 'ipv6', _('Enable IPv6 negotiation')); + o.default = o.disabled; + } + + o = s.taboption('advanced', form.Value, 'delay', _('Modem init timeout'), _('Maximum amount of seconds to wait for the modem to become ready')); + o.placeholder = '10'; + o.datatype = 'min(1)'; + + o = s.taboption('advanced', form.Value, 'mtu', _('Override MTU')); + o.placeholder = dev ? (dev.getMTU() || '1500') : '1500'; + o.datatype = 'max(9200)'; + + o = s.taboption('general', form.ListValue, 'pdptype', _('PDP Type')); + o.value('ipv4v6', 'IPv4/IPv6'); + o.value('ipv4', 'IPv4'); + o.value('ipv6', 'IPv6'); + o.default = 'ipv4v6'; + } +}); diff --git a/rooter/0routerspecfic/alix2d13/Makefile b/rooter/0routerspecfic/alix2d13/Makefile new file mode 100644 index 0000000..baa4245 --- /dev/null +++ b/rooter/0routerspecfic/alix2d13/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=alix2d13 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/alix2d13 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for alix2d13 + PKGARCH:=all +endef + +define Package/alix2d13/description + Helper scripts to install scripts for alix2d13 +endef + + +define Build/Compile +endef + +define Package/alix2d13/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,alix2d13)) diff --git a/rooter/0routerspecfic/alix2d13/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/alix2d13/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..3c46608 --- /dev/null +++ b/rooter/0routerspecfic/alix2d13/files/usr/lib/rooter/special.sh @@ -0,0 +1,7 @@ +#!/bin/sh +. /lib/functions.sh + +mkdir /tmp/sysinfo +echo -n "PC Engines Alix.2D" > /tmp/sysinfo/model + +echo 'SDA="'"sda"'"' > /etc/sda_drop \ No newline at end of file diff --git a/rooter/0routerspecfic/apu2c4/Makefile b/rooter/0routerspecfic/apu2c4/Makefile new file mode 100644 index 0000000..d021b91 --- /dev/null +++ b/rooter/0routerspecfic/apu2c4/Makefile @@ -0,0 +1,33 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=apu2c4 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/apu2c4 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + DEPENDS:=+kmod-leds-gpio +kmod-crypto-hw-ccp \ + +kmod-gpio-nct5104d +kmod-gpio-button-hotplug \ + +kmod-usb-core +kmod-usb-ohci +kmod-usb2 +kmod-usb3 \ + +kmod-sound-core +kmod-pcspkr + TITLE:=Install scripts for apu2c4 + PKGARCH:=all +endef + +define Package/apu2c4/description + Helper scripts to install scripts for apu2c4 +endef + + +define Build/Compile +endef + +$(eval $(call BuildPackage,apu2c4)) diff --git a/rooter/0routerspecfic/b1300/Makefile b/rooter/0routerspecfic/b1300/Makefile new file mode 100644 index 0000000..d61dae0 --- /dev/null +++ b/rooter/0routerspecfic/b1300/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=b1300 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/b1300 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for B1300 + PKGARCH:=all +endef + +define Package/b1300/description + Helper scripts to install scripts for B1300 +endef + + +define Build/Compile +endef + +define Package/b1300/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,b1300)) diff --git a/rooter/0routerspecfic/b1300/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/b1300/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..95767a9 --- /dev/null +++ b/rooter/0routerspecfic/b1300/files/usr/lib/rooter/special.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +LED=0 +SM=$(uci get system.led_wifi0) +if [ -z $SM ]; then + uci set system.led_wifi0=led + uci set system.led_wifi0.default="0" + uci set system.led_wifi0.name="WIFI0" + uci set system.led_wifi0.sysfs="b1300:green:wlan" + uci set system.led_wifi0.trigger="netdev" + uci set system.led_wifi0.dev="wlan0" + uci set system.led_wifi0.mode="link tx rx" + LED=1 +fi +SM=$(uci get system.led_wifi1) +if [ -z $SM ]; then + uci set system.led_wifi1=led + uci set system.led_wifi1.default="0" + uci set system.led_wifi1.name="WIFI1" + uci set system.led_wifi1.sysfs="b1300:green:wlan" + uci set system.led_wifi1.trigger="netdev" + uci set system.led_wifi1.dev="wlan1" + uci set system.led_wifi1.mode="link tx rx" + LED=1 +fi + +if [ $LED -eq 1 ]; then + uci commit system + /etc/init.d/led restart +fi diff --git a/rooter/0routerspecfic/d240/Makefile b/rooter/0routerspecfic/d240/Makefile new file mode 100644 index 0000000..2929121 --- /dev/null +++ b/rooter/0routerspecfic/d240/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=d240 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/d240 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for D240 + PKGARCH:=all +endef + +define Package/d240/description + Helper scripts to install scripts for D240 +endef + + +define Build/Compile +endef + +define Package/d240/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,d240)) diff --git a/rooter/0routerspecfic/d240/files/usr/lib/sdcard/sdcard.sh b/rooter/0routerspecfic/d240/files/usr/lib/sdcard/sdcard.sh new file mode 100644 index 0000000..0c1f7ed --- /dev/null +++ b/rooter/0routerspecfic/d240/files/usr/lib/sdcard/sdcard.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +log() { + logger -t "sdcard" "$@" +} + +ACTION=$1 + +if [ $ACTION = "add" ]; then + log "add" +else + log "remove" +fi + diff --git a/rooter/0routerspecfic/dir860l/Makefile b/rooter/0routerspecfic/dir860l/Makefile new file mode 100644 index 0000000..9efceea --- /dev/null +++ b/rooter/0routerspecfic/dir860l/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=dir860l +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/dir860l + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for Dlink DIR-860L + PKGARCH:=all +endef + +define Package/dir860l/description + Helper scripts to install scripts for Dlink DIR-860L +endef + + +define Build/Compile +endef + +define Package/dir860l/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,dir860l)) diff --git a/rooter/0routerspecfic/dir860l/files/etc/hotplug.d/iface/99-dir860-led b/rooter/0routerspecfic/dir860l/files/etc/hotplug.d/iface/99-dir860-led new file mode 100644 index 0000000..682d050 --- /dev/null +++ b/rooter/0routerspecfic/dir860l/files/etc/hotplug.d/iface/99-dir860-led @@ -0,0 +1,13 @@ +#!/bin/sh + +[ "$INTERFACE" != wan ] && exit 0 + +if [ "$ACTION" = ifup ]; then + set_gpio 14 1 + set_gpio 16 0 +fi + +if [ "$ACTION" = ifdown ]; then + set_gpio 14 0 + set_gpio 16 1 +fi \ No newline at end of file diff --git a/rooter/0routerspecfic/dir860l/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/dir860l/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..5ebc3e8 --- /dev/null +++ b/rooter/0routerspecfic/dir860l/files/usr/lib/rooter/special.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +# turn power led green +set_gpio 13 1 +set_gpio 15 0 + +# signal that we are waiting for internets +set_gpio 14 0 \ No newline at end of file diff --git a/rooter/0routerspecfic/ext-ssh/Makefile b/rooter/0routerspecfic/ext-ssh/Makefile new file mode 100644 index 0000000..03ac236 --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-ssh +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-ssh + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + DEPENDS:=+openssh-client +openssh-client-utils +openssh-keygen +openssh-moduli +openssh-server + TITLE:=Install scripts for SSH + PKGARCH:=all +endef + +define Package/ext-ssh/description + Helper scripts to install scripts for SSH +endef + + +define Build/Compile +endef + +define Package/ext-ssh/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-ssh)) diff --git a/rooter/0routerspecfic/ext-ssh/files/etc/init.d/sshd b/rooter/0routerspecfic/ext-ssh/files/etc/init.d/sshd new file mode 100644 index 0000000..44a0bd3 --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/files/etc/init.d/sshd @@ -0,0 +1,54 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006-2011 OpenWrt.org + +START=50 +STOP=50 + +USE_PROCD=1 +PROG=/usr/sbin/sshd + +log() { + logger -t "OPENSSH" "$@" +} + +start_service() { + log "Starting SSH" + + for type in rsa ecdsa ed25519; do { + # check for keys + key=/etc/ssh/ssh_host_${type}_key + [ ! -f $key ] && { + # generate missing keys + [ -x /usr/bin/ssh-keygen ] && { + /usr/bin/ssh-keygen -N '' -t $type -f $key 2>&- >&- + } + } + }; done + mkdir -m 0700 -p /var/empty + + local lport=`grep ^Port /etc/ssh/sshd_config | cut -d " " -f 2` + [ -z $lport ] && lport=22 + + #procd_open_instance + #procd_add_mdns "ssh" "tcp" "$lport" + #procd_set_param command $PROG -D + #procd_close_instance + + /usr/sbin/sshd & +} + +shutdown() { + local pid + local pids + local pid_mine + + stop + + # kill active clients + pid_mine="$$" + pids="$(pidof sshd)" + for pid in $pids; do + [ "$pid" = "$pid_mine" ] && continue + [ -e "/proc/$pid/stat" ] && kill $pid + done +} diff --git a/rooter/0routerspecfic/ext-ssh/files/etc/ssh/moduli b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/moduli new file mode 100644 index 0000000..cf28bd3 --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/moduli @@ -0,0 +1,407 @@ +# $OpenBSD: moduli,v 1.20 2017/11/29 05:49:54 dtucker Exp $ +# Time Type Tests Tries Size Generator Modulus +20170623034823 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EAE4E76CB +20170623034906 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EAEB63283 +20170623034928 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EAEE49C27 +20170623034936 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EAEF2BE1B +20170623034957 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EAF22F2D7 +20170623035029 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EAF68D3A7 +20170623035052 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EAF9A9793 +20170623035228 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB085C01B +20170623035326 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB1140217 +20170623035332 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB11ACBD7 +20170623035408 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB16AD187 +20170623035414 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB1737B53 +20170623035442 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB1B1C483 +20170623035454 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB1C8B93B +20170623035510 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB1EAD06B +20170623035525 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB208DA8B +20170623035553 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB2498F17 +20170623035604 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB25D82D3 +20170623035609 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB262420F +20170623035735 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB3376DEF +20170623035801 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB370E193 +20170623035916 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB426D9CF +20170623035935 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB44E559B +20170623035955 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB4777177 +20170623040012 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB4995E77 +20170623040023 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB4ACAF8B +20170623040032 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB4BB1ADB +20170623040120 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB52D4F1F +20170623040131 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB542306B +20170623040202 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB5899CB7 +20170623040216 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB5A317FB +20170623040224 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB5AEBE43 +20170623040246 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB5E190BF +20170623040254 2 6 100 2047 2 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB5EBE533 +20170623040334 2 6 100 2047 5 F740D04A6CFD4547DDBE874AEED3DF220F4ABD1EEA9BB022EDB3019835812EB327F3F0BBD0D137702856B499924C1A0D78D467EFBCB2215008FC3918FF88710ED5CA4F3554494F3AC374C8695B1DA006470F1C5C751825389DF3FBAC83DFEFAE2B07FA30E3B6B13D2BF9FAA27DCBD03FEB6847F08C3C6C89B04366A78D8C43E1E26B63ED5BB9A3E1AAE00BD4A4BF058B41B70E9F599C7DAE2E42701C68FDDEFE7213432E77342F785D64B723FF33A2D9C6F85F149776F898EF8BEFE3D03D2163974A3C0F13520F4BE92A246DED5A6FC997B2657D1A72A1210E881D0A0F14E93522268E3D8FFB84ABB3B9B064985E891C7C0DC09E166008A5E13A777EB649ECAF +20170623040448 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C4B50D13 +20170623040459 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C4C9F477 +20170623040510 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C4DDC50B +20170623040603 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C55E2BE7 +20170623040614 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C5715757 +20170623040626 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C58A0617 +20170623040632 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C5910FF7 +20170623040709 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C5E85ABB +20170623040729 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C61714B7 +20170623040745 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C6362DF7 +20170623040759 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C64F9EEB +20170623040829 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C6949627 +20170623040836 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C69F6763 +20170623040925 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C712B23B +20170623040941 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C7336C6F +20170623041004 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C76418FB +20170623041040 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C7B6A153 +20170623041049 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C7C6F12F +20170623041059 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C7D798EF +20170623041129 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C81D54F3 +20170623041311 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C919987F +20170623041314 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C91A831B +20170623041341 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C95422FF +20170623041350 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C9646B7F +20170623041354 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3C9662E87 +20170623041503 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3CA105123 +20170623041522 2 6 100 2047 5 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3CA3BE707 +20170623041541 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3CA620DAB +20170623041546 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3CA66FFC3 +20170623041620 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3CAB69493 +20170623041704 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3CB1C2B4B +20170623041709 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3CB1FD10B +20170623041747 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3CB7550DB +20170623041822 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3CBC63D2B +20170623041830 2 6 100 2047 2 EDB5FA2E865AD05F06510EFBFC71F9DFBAA5C1EEF3F6FDC2650C1D8C507DECA3422AE18746EA7D7BEA600C0AE9A0812A3DC02C099F8AF046EF014EC2A58734A716F156FCE4F19E3A9EB38F225A1CA0B868F70B3BE0CAE3AC2A20F330EF3CC33CB27D1FCB2D27505409144F957AC592567AC0B2A8099F6D58B546C7EE734FD806CDFDDE5F41C38966EB61005CA78D970BFA2C77F099BB19543B559AA118B6F303644D541E83B293138BEF5B8F0B0382ACA8DBDD693845FF6B7EE6ABF1B8B4733998F31DBF74F9CBA5145A0C5345EDC5B056CDCAA3AF605701C56651B8A968AD6D7E421DD3B5F3765865D5FDC55252F25C9661CD71A43A20B13A16CFF3CBD499AB +20170623043901 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5508B03E93 +20170623044452 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5509C5C937 +20170623044600 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5509F436FB +20170623044825 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB550A640733 +20170623045050 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB550AD6755B +20170623045124 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB550AE93B43 +20170623045420 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB550B6F1ED3 +20170623045805 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB550C20298F +20170623045930 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB550C5914BF +20170623050341 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB550D1A1773 +20170623050720 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB550DC219FB +20170623051801 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB550FBDD1AF +20170623052216 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5510842093 +20170623052416 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5510DBFCD7 +20170623052526 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB55110BB843 +20170623052831 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB551196B36B +20170623053119 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB551217A237 +20170623053458 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5512C20307 +20170623053734 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB55133990CB +20170623054412 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5514721AB3 +20170623054517 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB55149F4D0B +20170623055017 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB551583DD9B +20170623055422 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB55163A7903 +20170623055449 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5516475E5F +20170623055516 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5516556F37 +20170623055539 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB55165F8F67 +20170623055716 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5516A5CA13 +20170623055812 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5516C8A4A3 +20170623055846 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5516DBF96B +20170623060438 2 6 100 3071 2 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5517E20F03 +20170623060534 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB551803F1D7 +20170623060551 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB55180824C7 +20170623060759 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB5518622977 +20170623061152 2 6 100 3071 5 E795DA675C82260F11D7C50B677AE8A8D94BF342724BB06FA0D426CE2E83E8971A1BE2AC59516488B25D561568B14DBBFFB5F33686D2952409B9C20FC19A13CB91C9176420F59F464DC198E254B87C765DC12B885CF1A463858C3CB0A918AF66C6A2CA06A48B4D5BDEB5A56B24C36BA330488DFCBDD499957E755CCE704F183CB4549441A7D761C22B7F7CB66BE50F0A6591F17778F51E73544B765E83A3C00BD3309F8CE1B135A3DD481DBE8C2CEE54E8DDF1351015E70D9012662E69F654A5A9F68C416167685A1695C8139BA1825287C98680945506D5AB750BEB68C6D2B430E7E4043D0A00DECDA77F81A2432929F530C5BC0CBBC011095D897BD81FB98792345F5372BA53E53F31FB09730C58E8FDA9F7C1EBA0AEA4FE50B2B5CE146043CB18BFB3A12F06ED1D3287242D3D59E85E0A5E243626525D3EAD946126B9F32590011EEA0EDD5E2025037D51940B3E1A45B614A23F48278977535E3773F0AA2A24413F4A397AC0881582E8832C7B140C0BA4818A55C8620FD2BEBB55190DD957 +20170623061950 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21EBBB813F +20170623062054 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21EBE73A63 +20170623062250 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21EC3B7BBB +20170623062850 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21ED5538D7 +20170623063051 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21EDADBD87 +20170623063106 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21EDB14127 +20170623063228 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21EDEBD58B +20170623063242 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21EDEE14B3 +20170623063301 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21EDF542E7 +20170623063538 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21EE64F8A3 +20170623063759 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21EEC9D597 +20170623064815 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F0A8EB1F +20170623065609 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F21F5CB7 +20170623070150 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F32604CB +20170623070933 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F48C5ED3 +20170623071215 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F5044ECB +20170623071504 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F5815613 +20170623071625 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F5B8F8AB +20170623071723 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F5DE3F7B +20170623071945 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F645009B +20170623072445 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F721A837 +20170623072516 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F731AF17 +20170623073343 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F8B6F58F +20170623073442 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F8DA7A47 +20170623073826 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21F983F783 +20170623074239 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FA40B7CF +20170623074307 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FA4F193B +20170623074345 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FA61D323 +20170623074648 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FAEB991B +20170623074919 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FB5876F7 +20170623075011 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FB79557F +20170623075040 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FB88E5F7 +20170623075211 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FBC86DF3 +20170623075233 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FBD19D1B +20170623075313 2 6 100 3071 5 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FBE8A97F +20170623080026 2 6 100 3071 2 E787C1EA14A0022F3F98A02847D293441332B2EB8BFF8C4D74ECFF730CCA9D1AFC6433A6DD4BA7089EC18D8D314550FCDC6DA23FEFDE48622BB6FFD89AB71CC0BA6C8C0930593E85A442A9C589ECF35E17D9CC7E2AE713B3704D69B61EF6E79A41AE02ADBF7966DF94B1C6861795B7EDFA8D7418EBAEB47F26F158AEF3DB418FD1632DBB93B431204964B78C7AE9ED796E39F1B6DE1FEE4CE77815462F36342E80B44B052BADC06F78CFEA7D3D0B294C5C8E8E623F95F5D3C1A17D911A0E78FE7754AA4A440FE75498D9AA47AACF2FC2F716630AEF10950F1FACD4CF847A7E4B0C20F507A7322996DBC4D2250A99CB213CB95AAF7A8B6A0B5317BE8FF728D3A0A0AAEA1B86729DDD59566916640F9AF7A455145CE29CB58884CC2E9DD705B1E87D10E139945FBE70D20D718FED9AF202A22673D76128A5FCB2860419675ADB97512628C7C65C7078B0C730A258C8979912C18EC065367791A404C71318B78FE29CC115ECD74C4EFCDE86C35BD0CFC3ADC41B4F24243A262B251F6E21FD35417B +20170623082844 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069919E3F0A3 +20170623084111 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB47998481906991AE37AEB +20170623091322 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB47998481906991D857A5F +20170623095654 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB4799848190699210172E7 +20170623095828 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069921188C6B +20170623095901 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB4799848190699211B667F +20170623100423 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069921818383 +20170623101338 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB4799848190699223C1F3B +20170623101757 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB4799848190699228B3683 +20170623104910 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB4799848190699250221BB +20170623110231 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB4799848190699260AC373 +20170623110814 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB47998481906992672C113 +20170623113826 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069928D90D4F +20170623120249 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB47998481906992AC1BA3F +20170623121815 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB47998481906992BFC1B7B +20170623122456 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB47998481906992C7EB0CF +20170623123432 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB47998481906992D3D886B +20170623125910 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB47998481906992F34AA0B +20170623130350 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB47998481906992F8B1CFF +20170623131900 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069930BE28FB +20170623132006 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069930CCBBC3 +20170623134400 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069932B40887 +20170623134659 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069932E77127 +20170623140059 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069934031953 +20170623140936 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069934AC3B0F +20170623142309 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069935BCCF33 +20170623142743 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB47998481906993611A26B +20170623150027 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069938A6965B +20170623150107 2 6 100 4095 2 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB479984819069938AB78CB +20170623150738 2 6 100 4095 5 DCFD3F9E0CF8187E955D8AEB347A5E4250C2B78E67E73E1DCDB99D67EC98180AE5FEF9119D38E50CBDBF46C8B2F62240FF5E1B28FB01276B82DB7422A777AA30AC5A9423D9AC3D33C9FECCC85823BD1138919E8F831364B093CF13B11CDD11394AA8D2256D58264266F780EABBA494E99EF63EC1F69997D180ABBA50B091AFD7FF478DAFF435CE2529E5F8FC81316AB0EA636014E125715FC77D653B142734C93FCD825C28CB928D579E9ED2C6C11E89C64B9C4B91CA962FB11C824F302BDEF7F67D1F7AC95F52B49FD4A044101BA3BDDD59C7663AB270D24DC846B90925F615EBFA5182F261938182E301C83FDC027381BD0FA753C84E57CC51531E7D0C468988B67D0B312E73C65E21D93C69C7862553F60BC9B26C6B5FB68BEDA3D7B0770C1116FF2B88484C7FB29A9D46D01719E89CB76A25C1B8349E3F8DA38CC00B3C1502BA6775BE363D27FA71A72DE0094E6805DEABB343B4A6DC98CD5F5191017B4E1CB0E5EE2FA979642305B8FDE9EE6A26E469C03C8B806F9492C0C544D7A0FE7773B3940812AE6B76C447BC28AA8127D9A7FEB7F98B9720C889CE2FF4806225B012B06F2FC0737D2A73A3046BD7ACBF0A8CF02BB3FAB81A60A29C0AA5B3B731541F62B542F4EF8224C6BAF6A087D0A9FE43492E5CE13F855E80457A516155CCA04A6144E402A1A3D71D657556B9124837730953505EB4799848190699392AA267 +20170623152234 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988DA657F33 +20170623152823 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988DAD58DFF +20170623153243 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988DB1F719B +20170623153719 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988DB76316F +20170623154606 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988DC289BA3 +20170623155435 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988DCCFF757 +20170623161905 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988DEC7BD43 +20170623163928 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988E064A38B +20170623164410 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988E0BD160B +20170623172908 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988E467E87B +20170623174045 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988E54CE16F +20170623175902 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988E6CA185F +20170623180229 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988E706D14B +20170623180811 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988E76F7CD3 +20170623180923 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988E77E8123 +20170623182724 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988E8D82A2B +20170623185420 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988EAF9DAE7 +20170623195226 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988EFA2202B +20170623195633 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988EFEED5BF +20170623201051 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F10F59CB +20170623202959 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F2921927 +20170623203734 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F32287EB +20170623204218 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F37F8B03 +20170623204329 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F38F411F +20170623204840 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F3EE7B13 +20170623205709 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F493374B +20170623205814 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F4A24813 +20170623210627 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F53F787B +20170623210958 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F57EC8EB +20170623211248 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F5B1A9D7 +20170623213826 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F7B2A7AF +20170623213924 2 6 100 4095 2 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F7BDBA73 +20170623214723 2 6 100 4095 5 F2D0058FA043FB189699D118DE484B66A10DCE703B27209CFC6D23D9178067C9D560D7D8BA9D4439A22AED66322F25D886C0A5CD41821B49AAE3D7A7B72F9B0E2D823709AF5444C7E9474DF5867E605E638923A2FAD546A86B8014BA460D238A939B445D7489C91977B54AB531D75B0F4264F187218F885129751EC78654F4B21191365FEA1B7FEFC40842BBC07C4F1D1AD153F6A39B582406F6B5895336A1199F7556EE957EAC716AE6678CBE5390730F0EBB3CC5210242A80CB128BFD747ED1B61AF6BBD5B5DC07B34C5CA7AF73D1EE973B93E13918801AEFD674DF92A0AD84BFA2A8CEE1AD26140DA1D5FC0C450A1EAEBC88F8EA8E703A0F3A814E1F6975AA5BE732473575D16F137D2CE5F7A546CE4371ECB5E8052295E122A9CF89A026E2D09BDE56B8B04CC4CAE66CD0C5E0DFE30695DD798C50E39C911C887FEBACAAEFD2BFE7D454E051C432D66AD84680DA7C126F1A9C7C540283CCB863B9414BB536BA358259104ECB406B4976F97558FA4E5854888A8D13C96A14025DA0C55F869F6AF954B1E7AA1D317262C52099860E870A7EAF72F9910ACA809FF2DEA37FCA3EFB31FD43A308E4138E40178BEAC0FBB0E79ED7D1DCF8F8A81A4ABBFE6749F4C1B96BD65A14822490BC0A71E854BC8077C7A8F2C6FE308F86DEC97F600A4A0015F086B021F7F0BCAFDE3DA4D7E38A9AA1E992539389E99412FD22988F8513E37 +20170623233949 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D915376BC3 +20170624020214 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D918FF036F +20170624030028 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D91A80668F +20170624033630 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D91B697BC3 +20170624052652 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D91E5556DB +20170624075515 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D922262F73 +20170624103157 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D92638CCD7 +20170624120558 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D92895C273 +20170624130210 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D92A0429E7 +20170624131317 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D92A441063 +20170624132538 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D92A8E794F +20170624133715 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D92AD26E07 +20170624145051 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D92CB7412F +20170624163751 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D92F668E7B +20170624172739 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D930A8FC4B +20170624174055 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D930F6B80B +20170624185924 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D932ED85B7 +20170624220917 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D937BF2B3B +20170624222456 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D9381B839B +20170625033902 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D94007305B +20170625053719 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D942F8C1E7 +20170625062259 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D944178FAB +20170625072908 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D945B1B3DF +20170625075138 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D9463A10C3 +20170625080610 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D94691AE5B +20170625112146 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D94B5B8CDB +20170625113648 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D94BB43777 +20170625131459 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D94E2020A7 +20170625141110 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D94F7F2B87 +20170625144415 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D9504A46D3 +20170625145639 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D9508CDF97 +20170625203254 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D958CDC1DB +20170625215049 2 6 100 6143 2 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D95AA6BE13 +20170625220255 2 6 100 6143 5 E30D9BCD65DA0EAEF6A1D4D083834D4724538836AE04DFB6A7DAF235F5D9992B7E42128D43E229BF4906EF0C6A27F60B95A1FC514C2D55A0D616B3B6924F08E9C0BCD8AE1CB624F645785C2AA552C94E125D6602CF63CF52014A1B0A4AE0DE823B03B6ABFA25839ABC3E8E050C295B8B3471EC58EAD9B659294C72EA65229E4E8EB21CA79CBB41BB552118A3CD32108E51D5FCE5C46A6CD03E4246CB57E32BAA09B15503FBFA4F4C943B2378F10EE312C1F12A14010AFD1698B8EBCCFC8D0DF17829A153199154EBF9E40FD81B8E1AF5881D0EC1D3BEDB2D0F1DB9C44C9D8E7047310623D4FAAE28D2C16612CFB9AE9A8FD05B8FE22930346ECF7B21B5800778EA0D5D3B7BDF18B03ABF33C9D0B4648CF687ED229C811CE290CFAF94F9C9AF4EC3E47480955E5C81E85DA9EBCE99652DA07225C7CCEF39E224556E48D6371981C7232E00F3419F7B335FF36FE3989558277654DB356063ABC8F7BD0EF828B40D3BFC06D12FEC51278ACD32C3B67D4E2A0BBA1E20BDDA06DB9AF6AB250179DE3332EAC0A6D381963B51E8E167B8285BA3E6538B1D38B16B32196ABE009ADFDAF5E686E0107F76ED10414B6249D6895188456505CDB897FFCCEB8931802F87C02DFDC62825C6255DF2654712BE230CC86A30229D9E3438DB35CEED8F8447B9209CDECFC1776D2C43B4B98E9EEA3F4C049C1287CDB4540D395A4BC992602150CCC0479597E221E201B778DCA9701C517C89B95004FC19373ED9755C90FF32C44013678876EAD3FE5E637BF2F1959130EAF79E7A93088F52AA0AC993324294536CF3787C3A3F06F2DC201A070967E6F4525803DC83F5160B560465A4CE4BF20315858BE0E62A07C55B3A772CBF93DE99AADFCB304D2B544A9F17A22C2BEB791D98F714CA7CFF701CB7CAEC55C292A25A147935D7BBD1E66F2ED3EBC66E763209169033CE5A2D9884DC0CBAFF37517372544E1EB780A26CC71E5649EDFD5DA2FCFB58093D74D76FC2DAEC54567104701C31E3872C15BAC5F2A96833EEDAB9B7FF731F827DB3273D271BA8F9DE06181C1E38D031896971D801C571954337D95AE8D4FF +20170626000351 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973A06777EB +20170626010044 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973A1E685DB +20170626011405 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973A237A0AB +20170626020723 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973A39C76DB +20170626021405 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973A3C0D837 +20170626025354 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973A4CB1E73 +20170626025848 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973A4E33427 +20170626034407 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973A60D840F +20170626042648 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973A7271AD3 +20170626063327 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973AA7A8227 +20170626073301 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973AC001F7B +20170626073912 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973AC204247 +20170626083935 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973ADB29CEF +20170626085130 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973ADFA675B +20170626103016 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973B0702723 +20170626110918 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973B1648BFF +20170626113343 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973B1F924B3 +20170626150922 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973B78B107B +20170626162428 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973B972EB6B +20170626171558 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973BAC16547 +20170626231518 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973C3C4E533 +20170627001636 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973C53DC917 +20170627023229 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973C8A24E33 +20170627055348 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973CDB0A037 +20170627085558 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973D234059B +20170627111046 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973D57B1B3B +20170627114331 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973D63E6527 +20170627143549 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973DA76351B +20170627150713 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973DB2FF40B +20170627151417 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973DB566CC3 +20170627162358 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973DD096627 +20170627175138 2 6 100 6143 5 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973DF2B3477 +20170627180034 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973DF5CD463 +20170627192816 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973E16B337B +20170627194138 2 6 100 6143 2 FE3AFB7EA9CBCB633757EA982ED0DDFF120459E69D35DB36ACC5F69B04A5CCEE59A0312A97687F2B3DBC20917F4BF0B16D97B75EDCA16B58BDEB8BB1A726F6CB8BF5D7FC483777129A1C19CB559943EF201323760672C63859E830C6E99AFE5DD7A4E89BAD41C63B687558DD277F4E06A29D1E14A21CAA6FDD4E6F21EB8B146F2C04F93B1C94234E6295F2F8773B16BA3D51758841EA48ADD1A626E252DB3B78594B4586AC9E9EAF100F294ADC82BEBBF8CAB96B671EE7050B42733EB741107C5D2199D305C84F93C6AEEE6BD607DB7C0EFED773FB1DB73B04EFA72EB36111B99EBE6EEE899307FD288329FB2DB7E81776AEF0F935FFEE77611BDCFEC309F97EEB6E36FE42CA4C8EFAA0B4B93F5D83606B8FA7B49DD1DBB8F828B9C805381CB5DF4AC7FFAE27C62CBCD2FE80BB4157EB7F3267041255AC2F7EA3B450951878166049E5FF1BD3B361082FB184E342DDA1961ACFD90944F37E09A06AFE463AA9AA66EE699D28C4D109F3E8111CF4D625161B2855C11593AE408AE44DC026091119744FF09A4AB3C00717ACA004E26ACA53BF6444D839CF477A56FEAFFBF2E4CB946512815269D8E3C163FC29288A917A4A0ACC6DF54454CE2D54AC79AE05BF816DE1E3E9D3A9CC69DBE674880F98ECB8D8D4C4247AC07BC9B7C40FB89C4B9D4DA4604B37D15047DFB28C5D241CDFA327C3996872A0C05B84342F81A308D7796CA4A4038E47A5D4658F757C3F9645F11DEA92AE4D2E77FDB1A5D12519FF947F39A68152528CB02F915894D728C0E755B8BC4A99FCFC778A4099558A06D5FECC4C22DAA7E23C3B5E8E99B5365D5046C8C65846D949A521C0B25EFE5F5CD0845F09C29C096C4A80755120A299EA652B204775E53B2D521F366F4EF9FA65B1D8CB048295C39BE92667200E2889B1577CBD0AC23B2280B758A3650BE60D55F215DBF166873592253B1254968B5A46A61C792A153342C3ADE408676F4B27B7F22C50B079D0E32AEA134168A53A36F18E2FFA2459EDBA89BEC13D19C342235F6E9CF8F721B608F6297A3486173A7D5CED5E2AF6343775668C1B1FB0B745157973E1B23A4B +20170627235654 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6CE22848CB +20170628025708 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6CE4C7FC03 +20170628090844 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6CEA316C0F +20170628104935 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6CEB9D111B +20170628114328 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6CEC57837B +20170628155547 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6CEFEB085F +20170628161354 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6CF024A37B +20170629103301 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6CF75BD46F +20170629121023 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6CF8B74F97 +20170630003105 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D0331EC63 +20170630052003 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D04F2C61B +20170630145450 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D0CF7BF93 +20170701010810 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D1578081F +20170701015400 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D161119BF +20170701082405 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D1B5FB48B +20170701092427 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D1C2B0E47 +20170701161137 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D21ABD21B +20170702022204 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D29CF7033 +20170702023811 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D29FB9AAF +20170702062241 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D2CED4213 +20170702082528 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D2E88DA5F +20170702151719 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D33FAA757 +20170702175101 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D360021F3 +20170702200102 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D37A9C6C7 +20170703011731 2 6 100 7679 5 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D3BCD4977 +20170703155054 2 6 100 7679 2 E411B879FDA69428A30BDE74B417706E5936E16C5E1F2B64A07EAE1D69C857C23126701460740D93467EB3A3386827E658069CAC4D55CC4929493C193D53A0D91141135B2F0B19E659BB541883E569D38B329761EDF3C409D34A49870356F3723AD2F720383E49B1752B837DF80F48632A469A0A96AC8F02E5B766B590D722B5BD3ED9191BB70C1D4044A3D5CE850489216C3184D73BAE2B655D76B30EC1851951A756E2A45CD1FF82A83BDC1803005034BEB2EAC35FF7362831D8FBE02E07B1CCA351D47AD65B5282151FB2711A880410CED2C1CF205CC2072F6F244189F5BDB3AFDBA7FB02DD21C99D1EF72C1EF8BC6C68A273D16CB2D3CA190C30BDDEEAD7CA2E519F3AF806B5CBD436B971C1F1981EB35CB4007D129F43E660F7E47E807C889A1DC5FEFA7C304DB41B36982FEFB7390DC6C8E9474D3EEB84B3F757C367475EB1B4CB5B86F9507090F2CB37533E2B96BBC6F75B3BF1F4CECF18F67E7492A681845CF5AFA1B70FB3B0A09CDD3375BCF716CBF2A594533D157CB6C4008CF8C4818C9418E44A995028487B0346BD399BFB431CA94B3FC2AF9822520153105ADACEBE719CC24D1D043AC2AC24BD41759AA452000C43CB885D5F0D71DC2451A2C5C04B0B085BD23B5295B7A109DCD729C34479D51EAB4617FDD163128B25F5803B262C3D97E2D63B3E84D85B67ECDFDE6FA377E208BD2EF867072D341AC731338268AD82285DD6D219DE44EB0588E477CBFCD5F5C068D2FA877339424F324012D346C3E2B3C4408E4FD84535C5D4EA02137ABE0426BC4C3AD6EABAA221579CBA22023F8204ECCC98D143652DEBF5869CD73A81C0E4C6FC9A22F9E648B6783AA1D0F0A1F76B1C4E8692339A6A259F3D8419CF7FD22A26023678BFE4F70C79E7F113882E6C7A0606C5AA9094DB161683E43CCEC8C73FEBC7B82617B90541C2BC15EBA18B55E430373CF21DD235BA332EE6D7A6D042BAB4DEF94939AAD2A1F6FD235B09CA6CCFB45A614C79F3C83253B82BB73826DD22127F3F14292A9B682D607D6C9313DF5324712F976C8978AEDC97B40095E66BF850BCB83F477E1F5AB045844EA5CA0652C7C2C284B90FFDCAE2D5F3C165F66FCE871A5D0AFAA158E77099BFA7A969C8F3425E326D24E7E875D588B5E652ED331ABE4A72AFF7D89CFA9D55116B2610AEA4D1D16BCE1FE8D22849827677FEC8EC9864F5A4B874E7AA3228E31DACECA3ED7E1F31675CCA03E599E748BBCA483821DDC5F1C7ED376EDE7A650AD06CE3FC4E76062354B7D89093EBBF9717CED067846349E8BBEEC4CDDE0907F2DD1C31125F1DBB7B9A94E07677C4EBC756A5ED3D8DB30FB5772328272C6D431F42D3 +20170704184253 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936A2722BB3 +20170704204537 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936A4446CCB +20170705051520 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936ABC7F083 +20170705084652 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936AED1CC73 +20170705094007 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936AF8A26FF +20170705115139 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936B15913CF +20170705123819 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936B1FD105B +20170705150548 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936B411305B +20170705152103 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936B43D87FB +20170705174143 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936B637D557 +20170706120313 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936C5C0BE63 +20170706131942 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936C6CA2F0F +20170706141404 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936C781A68B +20170706153843 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936C8A1C2AB +20170706173242 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936CA322EEF +20170706183451 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936CB02939B +20170706184330 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936CB163C7B +20170706195815 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936CC15613B +20170707002909 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936CFBE39B3 +20170707012259 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936D06F0ADF +20170707064939 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936D4E0A703 +20170707065604 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936D4EE0BAF +20170707120623 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936D9082CA3 +20170707121752 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936D928FC67 +20170707164931 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936DCD75823 +20170707220455 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936E0F28243 +20170707233018 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936E20BF7B3 +20170708014205 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936E3C89587 +20170708023140 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936E469C123 +20170708053646 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936E6DBCAE7 +20170708071735 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936E8297A7F +20170708072409 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936E836D247 +20170708102649 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936EA984FCF +20170708144918 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936EE06AB6B +20170708163647 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936EF6DD803 +20170708181531 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936F0B07D83 +20170708234000 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936F4E4D5BF +20170709023719 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936F727B0C3 +20170709063946 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936FA3DA1B3 +20170709093311 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145936FC71EB57 +20170709151341 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D14593700D34957 +20170709162318 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D14593701B3041F +20170709184215 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D1459370374B3A3 +20170709215933 2 6 100 7679 5 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D14593705ED75E7 +20170710000252 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D145937077174C3 +20170710052851 2 6 100 7679 2 C0388038628CD48D5377C99911D89CEDF70AC54721EE6974975D61C9E25580D2108B48CBCDB8B647B271FA822546C00580DB013D19EE5A49EFD9AAECA2036A83BB3E2F96C3E7CB273AA9ACEFCA5A3E4C7C8FCF3332DE11288D8BD76E17B4C530F5F6EFB0D757F63E3B2B519EE960FA8206DF81E7B9DA463CE389E3164588BF5B66355D481DC620F0B2F352782105DF3AB86076DD7D612CE9839CB251D5C975166859A41B740E08E66B746B710479FAA430E2891E60647E04FE71D8F8BC9A6BCD20CFB42299142DC016E672CC350D497809379F54F6F3D1649ADCE72ADECEAAE1ECA85EEE8006700379DE3687A67AF796E1F317815461CFF6E58615CD453265612315FA8F99DC65D9CC218004671E43CE58C9F54862D86B58FD71212199A2A562B1AB9604BF43676A403E8EA56A69E68F1CF0C60C83B8EB31D9C0A23D8410C3A6898D749CAD8CDA9F17A224536BD08436B25E50BA67BAD09276BB55583CEDF48AEEFFD8FA3DBE4F609760DF1EDED136B38792CD164D2EA3C5443F0D8F9117544A9A6AAC615ADE01440B7948B2B53BC3F7218DEDEB16D23C3B0C2AA4BEB99F9A9225D87B6CCB037D8E9A2918C20FE9F2BFF429FD0F23AE370E820842AEDD823DD5B6DDD7F4AD3A06735A2E4144DBABEA5DD83A6AA98EED5F6F3021C246FBABD280986A1E7A24CCBE11BC3050CC04DB566277CECBA8B5BDC1D15E1F066B25B668C7B87EA54894EC7559B64F1400934DCE1C06A10955988E3B3F4A40566B3989608404859335C53EBD6BEE21614EB7C954D543DBA7EB61555B7CED9D08EF560426DBCE3018FBEF788CF69AEAB433B692A9E28CBAFEFC048BD9AB423678D4DD5807329BCC417CF77EC7FD8E50B6D9A8D6B2017B24F6890557AF327980D086499B7C4ED6518B9C23DAB9571CA9E8E949C039C5CC002CBC9BDD08728D543143AFE577738AD309AB2493A8157272196B73C28A4826B37A8274198A4E8188CDADB1D7BB209C84D03500F79B9DFEC1E4441F34069CC01D6B9A57940914F56217C0F3A5CE0C75DE2815EE396D4AB00EC9695DFBCDD88EA6C8017CC29B1257EED39B50E0D075CCF9564D4B22F59F4B5E6667E4CACAC6B63D8CC1C9AB2CC6309A319E559D2062FB99D15B62F08E4DAD676698813D227FF8967B3B3830970E92277B2446A3C269A74FB437800824A8987DA3636A17A53C7E55C66077BE0FBD63441402F19C6C4E1F1C46185A3F3F5D7D7F553F0066EBFCF2ECD74CFC6DB48F6A458AE66EC12532B691FA3AE9A0C19809B3A1AF06340EFB012A33D484D272CA09D5862DAC5E3A00006F260BDE5CE74E007AB12A8F686373949308E574DCE7EA9D1459370B975DE3 +20170710074510 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C8898200FD23 +20170710114649 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C88984F315BB +20170711033842 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C88990A1C3A7 +20170711064933 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C88992F18383 +20170711070835 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C8899321BE1B +20170712081942 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889A5694573 +20170712175235 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889AC1C9503 +20170712184856 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889ACBA643B +20170712224446 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889AF76B1E3 +20170713034208 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889B2F38EEF +20170713034622 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889B2F6567F +20170713071216 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889B55B411B +20170713222010 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889BFD2C803 +20170714013005 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889C1EF6397 +20170714094721 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889C7A27293 +20170714141853 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889CAA42B27 +20170714204505 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889CEF31E77 +20170714205139 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889CEFD860B +20170714214942 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889CF9B7253 +20170714230801 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889D071D153 +20170715054028 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889D4C6B33F +20170715152910 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889DB4248D3 +20170715213011 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889DF38680B +20170716095854 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889E75F9737 +20170716115603 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889E896321F +20170717072754 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889F528B29F +20170718103850 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889FB304F4F +20170718123146 2 6 100 8191 5 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C889FC58729F +20170718203220 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C88A012AA89B +20170718211015 2 6 100 8191 2 DDFBC1CD4FB7E30639422038F1FFBA2CD3EC3915F3C923282C6588F6EB218FF7B24870C0FE4B48213AB0948E101686FB7B0093ED467B6CA413EDD4B0BFE2155AEBC4DA3D2DD0C78DA9AD989A0E989010D6D5E86A123C169E126F97826EE5F602FF641FDF642A107E7538CB61740CBAF69F6C7DC5DD4DF28998AB61B8672F0B74A3A8DD7D165828D69DCC1BAE4D45F707C3894E040BCC0AF7AA810A6D5CB89276217EB7AFAFE4966D68C10318E8C8CB23CA593E8057F29FF9154908B11D6530E6352F9406C81D9DAC5C298979320B4E0DD89203A1F680C8084154D0439DB6C53EDAF6FCC0E8682EC99D345180120AEC810CBB0C2F1B6D1B660ACEAAD5996A5D184659B6A1F11456BA6A5E94D223959D8171C030499A9DB458702CB35CA7E7CD75D26FF5E94640AB8740ECE82559784BB6D5CB4D041D053629BD3F4178077F3F7E280296C46A3F0FBC37813A1AA221FBA2612F0CFE56450E9B1F2C2AE278EC7A7AAB66D61FA9749FE997EDC31131091620897014D33B2386B490CFD80656B7D2EB08C9DA9928798986996D60F74D766EB8988E2FF676E38C587E7A6651AA28BEB8BB56EBBD6E641E92309AEAA671A5F2EC72629442D2C3A4C2B8E4304DC71B342CD116527832078E6B53C1E0A72909615B408E17625F7259ACA98E46359448FC141F57B51A069B8A402AE3A87E10AE7E910F3916BAC6CE716C539E825A06626673DE7EBD899A3982FCC599791E7CA964C0D37BB076708C03DC7C022980974025C0EA9B72CC3D0A03E4626E030E9C857ECF6B3807AC9E8E0F72098C7E80DAA05BFF60394A8374096878F015597DD5B22E65646A7DDC87B5F6AE68594DF39B0BDB2675A32369AD81FD62033146B8DA6A801E918572CBC70DEBA9F70D088D69425733ACE0084E60E7FCB459A5B71F74F711184B1AEA240834D28D049474BB2E7ED1B17AA2B5EB7D274341456834320BE8FB245B1C2B84A096E7E40573FEB7C2997ED16C8C2C62409B8064398ED220FA82C59E53AD7E864C24473FCC7F017B897D5855F092A9428957467EFD93F67D3FA302C578328A9484CD0496CC83BEAC96504F9601DA2048D25BF43B5A69E46234A164D854B89DF1DEDC36F0304BA5FC035B27E782087C3EC0A81840A3EC042204C63F9698CC74A818428039B23664C409529C4EDD822DF77819805023795EE625D524F12824C1F1FE99546DF75107AFFF7D424C4C3FB3D0BDA2E9BC0D93603457FFE44FABEAB1E6B62223B201D42784731BEE11E0FF0BF29C930DAF913F974739800522E2B9C4094475A5F35AA92E2939E5719EB4EE19446ADC9ECC7EE6BAB5D264C9E74AB6DE856D541146048341EB51734A34E33EF8D929F645E23FD902CB5676DA9C84C9F46490710DC8CF2AA922252C3885CBD8D0CB1D176CAFEB46A625C56BE949F487C6E35E2CE481F024C88A0186FF33 +20170719070720 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225378FA20B88F +20170719080355 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225378FABF2F5B +20170719081323 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225378FAD37237 +20170719083433 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225378FB0C1BEB +20170719124018 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225378FDE8D93F +20170720083815 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253790C2785C7 +20170720203303 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225379147CF99B +20170721064950 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253791BAF7AFB +20170721151849 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225379217C124F +20170721220636 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225379260D3263 +20170722033935 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA22537929DAE9CB +20170722155118 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225379320A3B27 +20170722181755 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA22537933A7A623 +20170722212038 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225379359D2C63 +20170722230812 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA22537936C5DA37 +20170723005838 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA22537937F9469F +20170723041453 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253793A1DBF1B +20170723051250 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253793AB9FC9B +20170723112206 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253793EBF09F7 +20170723140224 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253794072005B +20170723170945 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225379427689A7 +20170724050156 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253794A23E407 +20170724065019 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253794B47E553 +20170725032628 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA225379588A6BE3 +20170725142722 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253795F8CFE9B +20170725192821 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA22537962B35BAB +20170726032919 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA22537967BE1D7F +20170726062511 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA22537969930233 +20170726073958 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253796A4B8B7B +20170726144150 2 6 100 8191 5 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253796EA9D3DF +20170726150548 2 6 100 8191 2 D84B8E9B7259F34AA46062684AD05873FD407C5FA804FFBC429D0DED5B497259FFF7F3C26D7A4C21592FCD658B607A5BDE7C4EAA7F5A3B6B713EAEDD5D0D47029CF51556BAFBBC91819DDA500332F7CE6777565C34CE56ED26BFE90830291C460891DDFEBF4FFFE5F217602081211E73EEC97612AC2C9FE8988738F0DC0FD2241B3C54357109D82FAAB532DB9C18B53B543D43B533FD67E36547972674968EB83AEE7EFC9F2AAF2C610C452EEA89A4FF5089BA6922F35128A844F6350A70671DD53C205AC7A75A1659CD3E57D385AB0BD78AF14DC129B1172884F1FCF5D795B6031A2BEB2410948A422D21AD3A215C85720F5EE695E235E36832E0A559DACDBD2B7CA3A1317CA005A963B49E3337829C40974C70F47540D89AAE625A1FD110874DC13D6E7B5711021F0CFD94C46D87582EBFF78EB2412B6D91DC0250A0B805F5E3B096ACB247C2A247A39164337FB3CB818AD4A950E6347B801DA742E5B532F4FC48815AA62B894FDB23B6E4D448DB62713AA46CC33C7D83D60A44B2B70FE8D841A56A4150A01C82B19CB93AE0AAA65E765EFF95933AC55742E0240744158B9CEF9DA8E18C3736BC8894306BF86D9B927CD62252ABFD39A3B352168336404C6B5F0DB4AEE518069274266E0C424F45D487B500BC087F49B53B0FA822D306D8B272E66C035569FFF1A191D354728253419E5B49115B88EB94E8452A28A3D699E73709FFD95D30430D45B730AF36D90C4DF464241C059375E8215E02294DFEAF8169BF1B47F7EE6F6479CB772D552D604589CE0A80BF7C38AFB2D8111D02A11D02264E2D1634128E53835E5815A92C19027DD08493C23344883FA5F2802A67E586221E2E22DFB8C67D75903F7211D52D19DC92DAC9C2E55D5D23E4B316F4F36AE24526C0D7CB5D43A5FA64CD621E9BBEB44ADAC0FB50237872CF13E0008D4D8F3B53B7F97FF8FD71E7B6ECCE359F5FBF3F6128DFD062C1E1177C6DDB97CBB9ED8AF082BF55D2DDF76920020A8AFCA08235752DE7542237D273F0324767F297BD98F573642B54D55AAEDCD9A5DB65DDF24F1E52489E22A8CDB204653F03A45261E20C965772CC92D71AD8A9DCA1205CA72C3AE330CA9ABFC93BD4C0591279661736B131AE905D5EB899BED456FE76BE26C4700FDF3238999B250DEF64F155FED724D3E38BDCAAD31CAC112BF39F0BC0CD3A906BEA43676E126616B51546C9E282117163EA7B38F255797A803F663EA16485FE4A8C2510409D3B6EF809EAC2BF897277A17A9C6E58709B57591FDA62321CEC2F545FCDB0AEEAF33ED378707C81711E003F1E77EEEE292F61E37FDC2FC4F97CEA96E1A4FB8643A9F18C9D6780BC5B815E43AF81E3B1D47D68D5A559C194F35A143B9EAE147D975BEF88D55AF1408BC1705C02F112616D08BFE6A44C0EFAC373CBB557E4953C79ACAA2253796EE14A73 diff --git a/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_config b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_config new file mode 100644 index 0000000..ea30e3d --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_config @@ -0,0 +1,49 @@ +# $OpenBSD: ssh_config,v 1.33 2017/05/07 23:12:57 djm Exp $ + +# This is the ssh client system-wide configuration file. See +# ssh_config(5) for more information. This file provides defaults for +# users, and the values can be changed in per-user configuration files +# or on the command line. + +# Configuration data is parsed as follows: +# 1. command line options +# 2. user-specific file +# 3. system-wide file +# Any configuration value is only changed the first time it is set. +# Thus, host-specific definitions should be at the beginning of the +# configuration file, and defaults at the end. + +# Site-wide defaults for some commonly used options. For a comprehensive +# list of available options, their meanings and defaults, please see the +# ssh_config(5) man page. + +# Host * +# ForwardAgent no +# ForwardX11 no +# PasswordAuthentication yes +# HostbasedAuthentication no +# GSSAPIAuthentication no +# GSSAPIDelegateCredentials no +# BatchMode no +# CheckHostIP yes +# AddressFamily any +# ConnectTimeout 0 +# StrictHostKeyChecking ask +# IdentityFile ~/.ssh/id_rsa +# IdentityFile ~/.ssh/id_dsa +# IdentityFile ~/.ssh/id_ecdsa +# IdentityFile ~/.ssh/id_ed25519 +# Port 22 +# Protocol 2 +# Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc +# MACs hmac-md5,hmac-sha1,umac-64@openssh.com +# EscapeChar ~ +# Tunnel no +# TunnelDevice any:any +# PermitLocalCommand no +# VisualHostKey no +# ProxyCommand ssh -q -W %h:%p gateway.example.com +# RekeyLimit 1G 1h + +# enable DSCP QoS values (per RFC-4594) +#IPQoS AF21 AF11 diff --git a/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ecdsa_key b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ecdsa_key new file mode 100644 index 0000000..54f6b67 --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ecdsa_key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIKZXyqVFZe7cRezB7I7Ro4NvdfdBaTCr81muBTDMXjAToAoGCCqGSM49 +AwEHoUQDQgAEPEAIY3VWttvqOPlt/LdQixGVohe8RMNlV+fuwInkTOliZgiCodD4 +jwmH3QnF8LAKs1bVndzKP7PIwQBWWXDxoQ== +-----END EC PRIVATE KEY----- diff --git a/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ecdsa_key.pub b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ecdsa_key.pub new file mode 100644 index 0000000..61f2c95 --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ecdsa_key.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDxACGN1Vrbb6jj5bfy3UIsRlaIXvETDZVfn7sCJ5EzpYmYIgqHQ+I8Jh90JxfCwCrNW1Z3cyj+zyMEAVllw8aE= root@turris diff --git a/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ed25519_key b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ed25519_key new file mode 100644 index 0000000..cca7f69 --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ed25519_key @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCAHDv6w/Pu5expKfxxcMjdwZSnZwRwLUNdzti8AQQVOAAAAJBx+cA4cfnA +OAAAAAtzc2gtZWQyNTUxOQAAACCAHDv6w/Pu5expKfxxcMjdwZSnZwRwLUNdzti8AQQVOA +AAAEAuYUyH5sKhsCf0WOtfm1YEf/I9Q5qS3R4aRZETsqlin4AcO/rD8+7l7Gkp/HFwyN3B +lKdnBHAtQ13O2LwBBBU4AAAAC3Jvb3RAdHVycmlzAQI= +-----END OPENSSH PRIVATE KEY----- diff --git a/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ed25519_key.pub b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ed25519_key.pub new file mode 100644 index 0000000..13946ef --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_ed25519_key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIAcO/rD8+7l7Gkp/HFwyN3BlKdnBHAtQ13O2LwBBBU4 root@turris diff --git a/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_rsa_key b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_rsa_key new file mode 100644 index 0000000..c358ee3 --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_rsa_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAy61T4RsAj2ebjwLoa3F/JkMCbgbg9XxyuvHq/w/mCYBy5s0/ +Js5gEahrKYRfez2xCwt7IXb6qOLenQHoD6YywhJZHo/g1HLtuOz+o44OVmwAOAN7 +P4k7igfe7tK7bJyb0zjOqQjiTxc5pkI07S1AEiLNo+BYdpzcRnpAaHrH8anN//6S +Z8xwzj4zI+9e2TkZUbtkPWjmk9Fa1Wlnt7fN1HSU/Rm72d5chUhQd85d5+WDkgzv +t21C2Wi7tUEsarR8Ac8RRfdfie6SilJsdmnlz+dgBWbWbUGyl9BI31ugIJfQqXx1 +PgzcHu7HROj1ab/8nrI3xpe9fdvmQQQxMnuORQIDAQABAoIBAQCtGJwttjYOqf3h +V5ZRIb7utIpPGdd7qg0TZd/Sbx+QObLtBcfC4idxOlIAkbhX08Ev4sz9TtGOUGji +xKkFC7kdiFxnBd4Mj7QKspdiRqtWtSimcgb/o1CPaUsEauHQV3Ry2VeA/sTedJ2Q +97llTEykXSGpQVPNUlg+KU2tvZNJhAMRRyEw0YkYTrOQntuDOGLb8iALOHCs87OW +GpNNsj/FBM+IoP89W/gvdPm/9ceDd1g8vfkxLQOs56Fnj1AaLJHgNoQtDS/LZaIH +y0z9eTKEP+HsQkthOp4zn3W7Rv1RDpUVgjBNOQgTNgDDIgINOFTwZ4YxVpyr9JZW +45lCg0ihAoGBAOk18Qf4fJHiUHoj/z3Vj0BYsb1xyN9YkHHFZhIk6Ws4Yx8RKM5R +I9amvJu9Tbkzjtu6+6eO7HJ7UMd3sfy2tqMpUq88FAWe0dvM0GYb6y2xeoUM/Ydq +lZon+dXkHpFJ4vwkSB7jV78SQVU2ofc2RD/npVaJQt6UfzwA1R36K6b5AoGBAN+U +kJtMgpUHE0U43aWJ/HOsaIYWKTpsWEoPImdDa8YqCmOUlNnQeKRFmTyMpuohYbhk +FxP+gFKkCxCLKPBLgDiHHHhg7TAiqA2gcHyAm0yN4jPgOq95ojYguk8ZbHYhjrsV +gQN9iWRiCPZo/tlAG4y570W4SbmEoNmKMsdtL3itAoGAauR9mRCtUFSyXHmZaWc0 +pOLCfTnlP3IhqvQ2x8RBdRLAZCICWSbZzW5Zbu0C7guSxGZdKL0a5ZJeQT88xr+c +0QaEzqsz5iuYty2Wq+bKEgSSSt/caTBSZ/lAy2gnFqMONlIO+JFty7d7WKqU7HHk +MIJlx1dc3hakhwU+qeHcFkkCgYEAh7eBCCQraBdBZVWdhez656SSVkKBiEtYVKxX +L+PHOiUu5T++E3HuqZjt6clfUOQuk2V+dM6aSo/1f3dZxHOwQ6AQcio0EHIZHRx0 +676Nhqzh0KeeOAJXqw+2yGkgY5z/LSViiSHdEqhH1Hvrpyi5EHWVfvbdGdYeZa70 +IAZxOIkCgYAUJlSS5/30F0oaANxD6We8vHifLzrYBiQouuED+aXpry/+Zq3kYhBy +Y5HPVDSbshwYBLQOJyOEN3ljG/ZzUJod+HlLu+YchAcPRS+svCFw4lNGvchOEz4y +RZGweJAyVwfEypWR5kI+O6TFmUZKkuTP4enkizqJ4/GPZVHHOUsdOA== +-----END RSA PRIVATE KEY----- diff --git a/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_rsa_key.pub b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_rsa_key.pub new file mode 100644 index 0000000..c94565f --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/ssh_host_rsa_key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLrVPhGwCPZ5uPAuhrcX8mQwJuBuD1fHK68er/D+YJgHLmzT8mzmARqGsphF97PbELC3shdvqo4t6dAegPpjLCElkej+DUcu247P6jjg5WbAA4A3s/iTuKB97u0rtsnJvTOM6pCOJPFzmmQjTtLUASIs2j4Fh2nNxGekBoesfxqc3//pJnzHDOPjMj717ZORlRu2Q9aOaT0VrVaWe3t83UdJT9GbvZ3lyFSFB3zl3n5YOSDO+3bULZaLu1QSxqtHwBzxFF91+J7pKKUmx2aeXP52AFZtZtQbKX0EjfW6Agl9CpfHU+DNwe7sdE6PVpv/yesjfGl7192+ZBBDEye45F root@turris diff --git a/rooter/0routerspecfic/ext-ssh/files/etc/ssh/sshd_config b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/sshd_config new file mode 100644 index 0000000..d142fa5 --- /dev/null +++ b/rooter/0routerspecfic/ext-ssh/files/etc/ssh/sshd_config @@ -0,0 +1,120 @@ +# $OpenBSD: sshd_config,v 1.102 2018/02/16 02:32:40 djm Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options override the +# default value. + +Port 23 +#AddressFamily any +#ListenAddress 0.0.0.0 +#ListenAddress :: + +HostKey /etc/ssh/ssh_host_rsa_key +HostKey /etc/ssh/ssh_host_ecdsa_key +HostKey /etc/ssh/ssh_host_ed25519_key + +# Ciphers and keying +#RekeyLimit default none + +# Logging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +PermitRootLogin yes +#StrictModes yes +#MaxAuthTries 6 +#MaxSessions 10 + +#PubkeyAuthentication yes + +# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 +# but this is overridden so installations will only check .ssh/authorized_keys +AuthorizedKeysFile .ssh/authorized_keys + +#AuthorizedPrincipalsFile none + +#AuthorizedKeysCommand none +#AuthorizedKeysCommandUser nobody + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +#PasswordAuthentication yes +#PermitEmptyPasswords no + +# Change to no to disable s/key passwords +#ChallengeResponseAuthentication yes + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via ChallengeResponseAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +#UsePAM no + +#AllowAgentForwarding yes +#AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PermitTTY yes +#PrintMotd yes +#PrintLastLog yes +#TCPKeepAlive yes +#UseLogin no +#PermitUserEnvironment no +#Compression delayed +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS no +#PidFile /var/run/sshd.pid +#MaxStartups 10:30:100 +#PermitTunnel no +#ChrootDirectory none +#VersionAddendum none + +# no default banner path +#Banner none + +# enable DSCP QoS values (per RFC-4594) +#IPQoS AF21 AF11 + +# override default of no subsystems +Subsystem sftp /usr/lib/sftp-server + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# PermitTTY no +# ForceCommand cvs server diff --git a/rooter/0routerspecfic/fscheck/Makefile b/rooter/0routerspecfic/fscheck/Makefile new file mode 100644 index 0000000..a18dcb3 --- /dev/null +++ b/rooter/0routerspecfic/fscheck/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=fscheck +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/fscheck + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + DEPENDS:=+e2fsprogs + TITLE:=Install scripts for FSCheck + PKGARCH:=all +endef + +define Package/fscheck/description + Helper scripts to install scripts for FSCheck +endef + + +define Build/Compile +endef + +define Package/fscheck/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,fscheck)) diff --git a/rooter/0routerspecfic/fscheck/files/usr/lib/lua/luci/controller/filecheck.lua b/rooter/0routerspecfic/fscheck/files/usr/lib/lua/luci/controller/filecheck.lua new file mode 100644 index 0000000..37898de --- /dev/null +++ b/rooter/0routerspecfic/fscheck/files/usr/lib/lua/luci/controller/filecheck.lua @@ -0,0 +1,37 @@ +module("luci.controller.filecheck", package.seeall) + +function index() + local page + page = entry({"admin", "system", "filecheck"}, template("admin_system/filecheck"), _("File System Check"), 93) + entry({"admin", "system", "do_filecheck"}, call("action_filecheck")) + entry({"admin", "system", "do_reboot"}, call("action_rebt")) + page.dependent = true +end + +function action_filecheck() + local rv ={} + os.execute("/usr/lib/rooter/filecheck.sh") + result = "/tmp/fsresult" + local file = io.open(result, "r") + if file ~= nil then + rv["result"] = file:read("*all") + file:close() + os.execute("/usr/lib/rooter/luci/luaops.sh delete /tmp/fsresult") + else + rv["result"] = "No response" + end + file = io.open("/tmp/fsro", "r") + if file ~= nil then + rv["fsro"] = 1 + file:close() + else + rv["fsro"] = 0 + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_rebt() + os.execute("reboot &") +end \ No newline at end of file diff --git a/rooter/0routerspecfic/fscheck/files/usr/lib/lua/luci/view/admin_system/filecheck.htm b/rooter/0routerspecfic/fscheck/files/usr/lib/lua/luci/view/admin_system/filecheck.htm new file mode 100644 index 0000000..be2e7a9 --- /dev/null +++ b/rooter/0routerspecfic/fscheck/files/usr/lib/lua/luci/view/admin_system/filecheck.htm @@ -0,0 +1,104 @@ +<%# + Copyright 2008 Steven Barth + Copyright 2008 Jo-Philipp Wich + Licensed to the public under the Apache License 2.0. +-%> + +<%+header%> + + + + +
                          + +

                          <%:File System Check%>

                          + +

                          <%:Check and Fix Read-only File System Problem.%>

                          +
                          + +

                          +
                          + +

                          Details of Check

                          + + + + +
                          + +
                          + +
                          + + + + +
                          +<%+footer%> \ No newline at end of file diff --git a/rooter/0routerspecfic/fscheck/files/usr/lib/rooter/filecheck.sh b/rooter/0routerspecfic/fscheck/files/usr/lib/rooter/filecheck.sh new file mode 100644 index 0000000..1ed3169 --- /dev/null +++ b/rooter/0routerspecfic/fscheck/files/usr/lib/rooter/filecheck.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +rm -f /tmp/fsresult +rm -f /tmp/fsro +if [ -e /dev/mmcblk0p2 ]; then + E2=$(e2fsck -y -v -f /dev/mmcblk0p2 2> /tmp/fsresult) + echo "$E2" >> /tmp/fsresult + E3=$(cat /tmp/fsresult | grep -o "aborting") + if [ ! -z $E3 ]; then + echo " " > /tmp/fsresult + echo " " >> /tmp/fsresult + echo " File System mounted as Read/Write" >> /tmp/fsresult + exit 0 + fi + echo "1" >> /tmp/fsro +else + echo "Not correct file system" > /tmp/fsresult +fi + diff --git a/rooter/0routerspecfic/h721/Makefile b/rooter/0routerspecfic/h721/Makefile new file mode 100644 index 0000000..ee1fb3a --- /dev/null +++ b/rooter/0routerspecfic/h721/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=h721 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/h721 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + DEPENDS:=+kmod-ath10k +kmod-ath9k \ + +ath10k-firmware-qca988x +ath10k-firmware-qca9984 \ + +ath10k-firmware-qca99x0 +ath10k-firmware-qca9888 + TITLE:=Install scripts for Dual-Q H721 + PKGARCH:=all +endef + +define Package/h721/description + Helper scripts to install scripts for Dual-Q H721 +endef + + +define Build/Compile +endef + +define Package/h721/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,h721)) diff --git a/rooter/0routerspecfic/h721/files/etc/exportgpio.sh b/rooter/0routerspecfic/h721/files/etc/exportgpio.sh new file mode 100644 index 0000000..311f49e --- /dev/null +++ b/rooter/0routerspecfic/h721/files/etc/exportgpio.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +for i in 502 503 +do +echo $i > /sys/class/gpio/export +echo out > /sys/class/gpio/gpio${i}/direction +echo 1 > /sys/class/gpio/gpio${i}/value +done + + +sleep 1 + +for i in 502 503 +do +echo 0 > /sys/class/gpio/gpio${i}/value +sleep 8 +done + +echo timer > /sys/class/leds/h761:green:4g5g/trigger +echo 0 > /sys/class/leds/h761:green:4g5g/delay_on +echo 1000 > /sys/class/leds/h761:green:4g5g/delay_off +echo timer > /sys/class/leds/h761:green:4g/trigger +echo 0 > /sys/class/leds/h761:green:4g/delay_on +echo 1000 > /sys/class/leds/h761:green:4g/delay_off diff --git a/rooter/0routerspecfic/h721/files/etc/init.d/custom b/rooter/0routerspecfic/h721/files/etc/init.d/custom new file mode 100644 index 0000000..ab68244 --- /dev/null +++ b/rooter/0routerspecfic/h721/files/etc/init.d/custom @@ -0,0 +1,10 @@ +#!/bin/sh /etc/rc.common + +. /lib/functions.sh + +START=10 + +start() +{ + /usr/lib/custom/custom.lua & +} diff --git a/rooter/0routerspecfic/h721/files/etc/init.d/exportgpio b/rooter/0routerspecfic/h721/files/etc/init.d/exportgpio new file mode 100644 index 0000000..bacc5ac --- /dev/null +++ b/rooter/0routerspecfic/h721/files/etc/init.d/exportgpio @@ -0,0 +1,15 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 OpenWrt.org + +START=95 +USE_PROCD=1 + +log() { + logger -t "exportgpio" "$@" +} + +start_service() +{ + log "H761 Gpio Setup" + /etc/exportgpio.sh & +} diff --git a/rooter/0routerspecfic/h721/files/usr/lib/custom/custom.lua b/rooter/0routerspecfic/h721/files/usr/lib/custom/custom.lua new file mode 100644 index 0000000..f3b56d2 --- /dev/null +++ b/rooter/0routerspecfic/h721/files/usr/lib/custom/custom.lua @@ -0,0 +1,38 @@ +#!/usr/bin/lua + +printf = function(s,...) + if pflag ~= 0 then + io.write(s:format(...)) + local ss = s:format(...) + if echo == 1 then + os.execute("/usr/lib/rooter/logprint.sh " .. ss) + end + end +end + +function sleep(n) + os.execute("sleep " .. tonumber(n)) +end + +function file_exists(name) + local f=io.open(name,"r") + if f~=nil then io.close(f) return true else return false end +end + +while file_exists("/tmp/sysinfo/board_name") == false do + sleep(1) +end + +if file_exists("/etc/custom") then + file = io.open("/etc/custom", "r") + board = file:read("*line") + model = file:read("*line") + hostname = file:read("*line") + file:close() + + os.execute("/usr/lib/custom/hostname.sh " .. hostname) + os.execute("/usr/lib/custom/wifi.sh &") +end + + + diff --git a/rooter/0routerspecfic/h721/files/usr/lib/custom/hostname.sh b/rooter/0routerspecfic/h721/files/usr/lib/custom/hostname.sh new file mode 100644 index 0000000..af84554 --- /dev/null +++ b/rooter/0routerspecfic/h721/files/usr/lib/custom/hostname.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +hostname=$1 + +HO=$(uci get system.@system[-1].hostname) +if [ $HO = "OpenWrt" -o $HO = "LEDE" ]; then + uci set system.@system[-1].hostname="$1" + echo "$1" > /proc/sys/kernel/hostname + uci commit system +fi diff --git a/rooter/0routerspecfic/h721/files/usr/lib/custom/wifi.sh b/rooter/0routerspecfic/h721/files/usr/lib/custom/wifi.sh new file mode 100644 index 0000000..273efd2 --- /dev/null +++ b/rooter/0routerspecfic/h721/files/usr/lib/custom/wifi.sh @@ -0,0 +1,30 @@ +#!/bin/sh +. /lib/functions.sh + + +do_radio() { + local config=$1 + local channel + mode="ap" + + config_get channel $1 channel + if [ $channel -lt 15 ]; then + RADIO=$config + ifname="$(ubus -S call network.wireless status | jsonfilter -l 1 -e "@.$RADIO.interfaces[@.config.mode=\"${mode}\"].ifname")" + if [ ! -z $ifname ]; then + iw reg set US + iwconfig $ifname txpower 30 + fi + fi +} + +while [ ! -e /etc/config/wireless ] +do + sleep 1 +done +sleep 3 +if [ ! -e /etc/maxwifi ]; then + config_load wireless + config_foreach do_radio wifi-device + echo "0" > /etc/maxwifi +fi diff --git a/rooter/0routerspecfic/h721/files/usr/lib/rooter/modem-led.sh b/rooter/0routerspecfic/h721/files/usr/lib/rooter/modem-led.sh new file mode 100644 index 0000000..d0422b7 --- /dev/null +++ b/rooter/0routerspecfic/h721/files/usr/lib/rooter/modem-led.sh @@ -0,0 +1,94 @@ +#!/bin/sh + +log() { + logger -t "modem-led " "$@" +} + +CURRMODEM=$1 +COMMD=$2 + +DEV=$(uci get modem.modem$CURRMODEM.device) +DEVV=${DEV:0:1} + +if [ $DEVV = "1" ]; then + case $COMMD in + "0" ) + echo timer > /sys/class/leds/h721:green:4g5g/trigger + echo 0 > /sys/class/leds/h721:green:4g5g/delay_on + echo 1000 > /sys/class/leds/h721:green:4g5g/delay_off + ;; + "1" ) + echo timer > /sys/class/leds/h721:green:4g5g/trigger + echo 500 > /sys/class/leds/h721:green:4g5g/delay_on + echo 500 > /sys/class/leds/h721:green:4g5g/delay_off + ;; + "2" ) + echo timer > /sys/class/leds/h721:green:4g5g/trigger + echo 200 > /sys/class/leds/h721:green:4g5g/delay_on + echo 200 > /sys/class/leds/h721:green:4g5g/delay_off + ;; + "3" ) + echo timer > /sys/class/leds/h721:green:4g5g/trigger + echo 1000 > /sys/class/leds/h721:green:4g5g/delay_on + echo 0 > /sys/class/leds/h721:green:4g5g/delay_off + ;; + "4" ) + sig2=$3 + echo timer > /sys/class/leds/h721:green:rssi_lte1/trigger + if [ $sig2 -lt 18 -a $sig2 -gt 0 ] 2>/dev/null;then + echo 500 > /sys/class/leds/h721:green:rssi_lte1/delay_on + echo 500 > /sys/class/leds/h721:green:rssi_lte1/delay_off + elif [ $sig2 -ge 18 -a $sig2 -lt 31 ] 2>/dev/null;then + echo 150 > /sys/class/leds/h721:green:rssi_lte1/delay_on + echo 150 > /sys/class/leds/h721:green:rssi_lte1/delay_off + elif [ $sig2 -eq 31 ] 2>/dev/null;then + echo 0 > /sys/class/leds/h721:green:rssi_lte1/delay_on + echo 1000 > /sys/class/leds/h721:green:rssi_lte1/delay_off + else + echo 950 > /sys/class/leds/h721:green:rssi_lte1/delay_on + echo 950 > /sys/class/leds/h721:green:rssi_lte1/delay_off + fi + ;; + esac +else + case $COMMD in + "0" ) + echo timer > /sys/class/leds/h721:green:4g/trigger + echo 0 > /sys/class/leds/h721:green:4g/delay_on + echo 1000 > /sys/class/leds/h721:green:4g/delay_off + ;; + "1" ) + echo timer > /sys/class/leds/h721:green:4g/trigger + echo 500 > /sys/class/leds/h721:green:4g/delay_on + echo 500 > /sys/class/leds/h721:green:4g/delay_off + ;; + "2" ) + echo timer > /sys/class/leds/h721:green:4g/trigger + echo 200 > /sys/class/leds/h721:green:4g/delay_on + echo 200 > /sys/class/leds/h721:green:4g/delay_off + ;; + "3" ) + echo timer > /sys/class/leds/h721:green:4g/trigger + echo 1000 > /sys/class/leds/h721:green:4g/delay_on + echo 0 > /sys/class/leds/h721:green:4g/delay_off + ;; + "4" ) + sig=$3 + echo timer > /sys/class/leds/h721:green:rssi_lte2/trigger + if [ $sig -lt 18 -a $sig -gt 0 ] 2>/dev/null;then + echo 500 > /sys/class/leds/h721:green:rssi_lte2/delay_on + echo 500 > /sys/class/leds/h721:green:rssi_lte2/delay_off + elif [ $sig -ge 18 -a $sig -lt 31 ] 2>/dev/null;then + echo 150 > /sys/class/leds/h721:green:rssi_lte2/delay_on + echo 150 > /sys/class/leds/h721:green:rssi_lte2/delay_off + elif [ $sig -eq 31 ] 2>/dev/null;then + echo 0 > /sys/class/leds/h721:green:rssi_lte2/delay_on + echo 1000 > /sys/class/leds/h721:green:rssi_lte2/delay_off + else + echo 950 > /sys/class/leds/h721:green:rssi_lte2/delay_on + echo 950 > /sys/class/leds/h721:green:rssi_lte2/delay_off + fi + ;; + esac + +fi \ No newline at end of file diff --git a/rooter/0routerspecfic/h721/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/h721/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..3f499d1 --- /dev/null +++ b/rooter/0routerspecfic/h721/files/usr/lib/rooter/special.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +wifi config +wifi up \ No newline at end of file diff --git a/rooter/0routerspecfic/mt1300/Makefile b/rooter/0routerspecfic/mt1300/Makefile new file mode 100644 index 0000000..15d2f31 --- /dev/null +++ b/rooter/0routerspecfic/mt1300/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=mt1300 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/mt1300 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for MT1300 + PKGARCH:=all +endef + +define Package/mt1300/description + Helper scripts to install scripts for MT1300 +endef + + +define Build/Compile +endef + +define Package/mt1300/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,mt1300)) diff --git a/rooter/0routerspecfic/mt1300/files/etc/init.d/mt1300 b/rooter/0routerspecfic/mt1300/files/etc/init.d/mt1300 new file mode 100644 index 0000000..7ed8cc7 --- /dev/null +++ b/rooter/0routerspecfic/mt1300/files/etc/init.d/mt1300 @@ -0,0 +1,23 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 OpenWrt.org + +START=90 +USE_PROCD=1 + +log() { + logger -t "mt1300" "$@" +} + +start_service() +{ + if [ ! -e /etc/mt1300 ]; then + uci set wireless.radio0.disabled=0 + uci set wireless.radio0.hwmode=11g + uci set wireless.radio0.htmode=HT20 + uci set wireless.radio0.channel=3 + uci set wireless.radio0.legacy_rates=0 + uci commit wireless + wifi reload + echo "0" > /etc/mt1300 + fi +} diff --git a/rooter/0routerspecfic/rbm11g/Makefile b/rooter/0routerspecfic/rbm11g/Makefile new file mode 100644 index 0000000..e100892 --- /dev/null +++ b/rooter/0routerspecfic/rbm11g/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=rbm11g +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/rbm11g + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for RBM11G + PKGARCH:=all +endef + +define Package/rbm11g/description + Helper scripts to install scripts for RBM11G +endef + + +define Build/Compile +endef + +define Package/rbm11g/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,rbm11g)) diff --git a/rooter/0routerspecfic/rbm11g/files/usr/lib/rooter/modem-led.sh b/rooter/0routerspecfic/rbm11g/files/usr/lib/rooter/modem-led.sh new file mode 100644 index 0000000..43033ac --- /dev/null +++ b/rooter/0routerspecfic/rbm11g/files/usr/lib/rooter/modem-led.sh @@ -0,0 +1,124 @@ +#!/bin/sh + +log() { + logger -t "modem-led " "$@" +} + +CURRMODEM=$1 +COMMD=$2 + + case $COMMD in + "0" ) + echo none > /sys/class/leds/rbm11g:green:rssi0/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi0/brightness + echo none > /sys/class/leds/rbm11g:green:rssi1/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi1/brightness + echo none > /sys/class/leds/rbm11g:green:rssi2/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi2/brightness + echo none > /sys/class/leds/rbm11g:green:rssi3/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi3/brightness + echo none > /sys/class/leds/rbm11g:green:rssi4/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi4/brightness + echo none > /sys/class/leds/rbm11g:green:usr/trigger + echo 0 > /sys/class/leds/rbm11g:green:usr/brightness + ;; + "1" ) + echo timer > /sys/class/leds/rbm11g:green:usr/trigger + echo 500 > /sys/class/leds/rbm11g:green:usr/delay_on + echo 500 > /sys/class/leds/rbm11g:green:usr/delay_off + ;; + "2" ) + echo timer > /sys/class/leds/rbm11g:green:usr/trigger + echo 200 > /sys/class/leds/rbm11g:green:usr/delay_on + echo 200 > /sys/class/leds/rbm11g:green:usr/delay_off + ;; + "3" ) + echo timer > /sys/class/leds/rbm11g:green:usr/trigger + echo 1000 > /sys/class/leds/rbm11g:green:usr/delay_on + echo 0 > /sys/class/leds/rbm11g:green:usr/delay_off + ;; + "4" ) + #echo none > /sys/class/leds/rbm11g:green:rssi0/trigger + #echo 1 > /sys/class/leds/rbm11g:green:rssi0/brightness + sig2=$3 + if [ $sig2 -lt 5 -a $sig2 -gt 0 ] 2>/dev/null;then + echo none > /sys/class/leds/rbm11g:green:usr/trigger + echo 1 > /sys/class/leds/rbm11g:green:usr/brightness + echo none > /sys/class/leds/rbm11g:green:rssi0/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi0/brightness + echo none > /sys/class/leds/rbm11g:green:rssi1/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi1/brightness + echo none > /sys/class/leds/rbm11g:green:rssi2/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi2/brightness + echo none > /sys/class/leds/rbm11g:green:rssi3/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi3/brightness + echo none > /sys/class/leds/rbm11g:green:rssi4/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi4/brightness + elif [ $sig2 -ge 5 -a $sig2 -lt 10 ] 2>/dev/null;then + echo none > /sys/class/leds/rbm11g:green:usr/trigger + echo 1 > /sys/class/leds/rbm11g:green:usr/brightness + echo none > /sys/class/leds/rbm11g:green:rssi0/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi0/brightness + echo none > /sys/class/leds/rbm11g:green:rssi1/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi1/brightness + echo none > /sys/class/leds/rbm11g:green:rssi2/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi2/brightness + echo none > /sys/class/leds/rbm11g:green:rssi3/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi3/brightness + echo none > /sys/class/leds/rbm11g:green:rssi4/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi4/brightness + elif [ $sig2 -ge 10 -a $sig2 -lt 15 ] 2>/dev/null;then + echo none > /sys/class/leds/rbm11g:green:usr/trigger + echo 1 > /sys/class/leds/rbm11g:green:usr/brightness + echo none > /sys/class/leds/rbm11g:green:rssi0/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi0/brightness + echo none > /sys/class/leds/rbm11g:green:rssi1/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi1/brightness + echo none > /sys/class/leds/rbm11g:green:rssi2/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi2/brightness + echo none > /sys/class/leds/rbm11g:green:rssi3/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi3/brightness + echo none > /sys/class/leds/rbm11g:green:rssi4/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi4/brightness + elif [ $sig2 -ge 15 -a $sig2 -lt 20 ] 2>/dev/null;then + echo none > /sys/class/leds/rbm11g:green:usr/trigger + echo 1 > /sys/class/leds/rbm11g:green:usr/brightness + echo none > /sys/class/leds/rbm11g:green:rssi0/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi0/brightness + echo none > /sys/class/leds/rbm11g:green:rssi1/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi1/brightness + echo none > /sys/class/leds/rbm11g:green:rssi2/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi2/brightness + echo none > /sys/class/leds/rbm11g:green:rssi3/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi3/brightness + echo none > /sys/class/leds/rbm11g:green:rssi4/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi4/brightness + elif [ $sig2 -ge 20 -a $sig2 -lt 25 ] 2>/dev/null;then + echo none > /sys/class/leds/rbm11g:green:usr/trigger + echo 1 > /sys/class/leds/rbm11g:green:usr/brightness + echo none > /sys/class/leds/rbm11g:green:rssi0/trigger + echo 0 > /sys/class/leds/rbm11g:green:rssi0/brightness + echo none > /sys/class/leds/rbm11g:green:rssi1/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi1/brightness + echo none > /sys/class/leds/rbm11g:green:rssi2/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi2/brightness + echo none > /sys/class/leds/rbm11g:green:rssi3/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi3/brightness + echo none > /sys/class/leds/rbm11g:green:rssi4/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi4/brightness + else + echo none > /sys/class/leds/rbm11g:green:usr/trigger + echo 1 > /sys/class/leds/rbm11g:green:usr/brightness + echo none > /sys/class/leds/rbm11g:green:rssi0/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi0/brightness + echo none > /sys/class/leds/rbm11g:green:rssi1/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi1/brightness + echo none > /sys/class/leds/rbm11g:green:rssi2/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi2/brightness + echo none > /sys/class/leds/rbm11g:green:rssi3/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi3/brightness + echo none > /sys/class/leds/rbm11g:green:rssi4/trigger + echo 1 > /sys/class/leds/rbm11g:green:rssi4/brightness + fi + ;; + esac diff --git a/rooter/0routerspecfic/rbm11g/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/rbm11g/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..dca81af --- /dev/null +++ b/rooter/0routerspecfic/rbm11g/files/usr/lib/rooter/special.sh @@ -0,0 +1,11 @@ +#!/bin/sh +. /lib/functions.sh + +MODEM_DEVICES=`cat /sys/kernel/debug/usb/devices | grep 'Sierra' -A3 | grep '^C:' | awk '{print $3}'` +if [ $MODEM_DEVICES -eq 1 ]; then + echo "Sierra Modem in BOOTHOLD! Resetting pcie0_vcc state." > /dev/kmsg + echo "0" > /sys/class/gpio/gpio9/value + echo "Toggled pcie0_vcc: OFF" > /dev/kmsg + echo "1" > /sys/class/gpio/gpio9/value + echo "Toggled pcie0_vcc: ON" > /dev/kmsg +fi \ No newline at end of file diff --git a/rooter/0routerspecfic/rbm33g/Makefile b/rooter/0routerspecfic/rbm33g/Makefile new file mode 100644 index 0000000..4fa676f --- /dev/null +++ b/rooter/0routerspecfic/rbm33g/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=rbm33g +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/rbm33g + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for RBM33G + PKGARCH:=all +endef + +define Package/rbm33g/description + Helper scripts to install scripts for RBM33G +endef + + +define Build/Compile +endef + +define Package/rbm33g/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,rbm33g)) diff --git a/rooter/0routerspecfic/rbm33g/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/rbm33g/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..ca8f81e --- /dev/null +++ b/rooter/0routerspecfic/rbm33g/files/usr/lib/rooter/special.sh @@ -0,0 +1,70 @@ +#!/bin/sh +. /lib/functions.sh + +VL=0 +do_vlan() { + local config=$1 + config_get ports $1 ports + if [ "$ports" = "1 2 6t" ]; then + uci set network."$config".ports="0 1 6t" + VL=1 + fi + if [ "$ports" = "0 6t" ]; then + uci set network."$config".ports="2 6t" + VL=1 + fi +} + +if [ ! -f /etc/rbm33 ]; then + config_load network + config_foreach do_vlan switch_vlan + + if [ $VL -eq 1 ]; then + uci commit network + /etc/init.d/network restart + fi + echo "0" > /etc/rbm33 +fi + +echo "1" > /sys/class/gpio/gpio9/value +sleep 1 +echo "1" > /sys/class/gpio/gpio12/value + +# 1 Check USB Devices, Rev=0.00 is probably a boothold device, awk reverses the line order +var="`cat /sys/kernel/debug/usb/devices | grep -E '^T:|^P:|^C:' | grep -E 'Rev= 0.00$' -C1 | awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }'`" +while read -r line; do + case $line in 'T: Bus='*) + if [ $ProdID ] && [ $Vendor ]; then + BPort="`echo $line | awk -F'[ =]' '{print $3$9}'`" + case $BPort in + '0101') GPIO_PIN=gpio9; ;; # pcie0 + '0100') GPIO_PIN=gpio10; ;; # pcie1/USB in USB 2.0 mode + '0200') GPIO_PIN=gpio12; ;; # USB in USB 3.0 mode + *) unset GPIO_PIN; ;; + esac; + if [ $GPIO_PIN ]; then + echo "Modem in BOOTHOLD!" > /dev/kmsg + echo "0" > /sys/class/gpio/$GPIO_PIN/value + echo "1" > /sys/class/gpio/$GPIO_PIN/value + echo "Toggled GPIO $GPIO_PIN" > /dev/kmsg + unset GPIO_PIN + fi + fi + esac + unset Vendor + unset ProdID + case $line in 'P: Vendor='*) + if [ $trigger -eq 1 ]; then + # 3 add logic to check against VID/PID from list + Vendor=`echo $line | awk -F'[ =]' '{print $3}'` + ProdID=`echo $line | awk -F'[ =]' '{print $5}'` + trigger=0 + fi + esac + case $line in 'C:* #Ifs= 1'*) + # 2 Found a device with only one interface, so we'll assume is a boothold modem for now + trigger=1 + esac +done <]], scope\)\nif ok then\nreturn res\nend\nreturn luci.template.render\(\"sysauth\", scope\)/;ba" /usr/lib/lua/luci/dispatcher.lua +[ -f /usr/lib/lua/luci/view/themes/material/out_header_login.htm ] && mv -f /usr/lib/lua/luci/view/themes/material/out_header_login.htm /usr/lib/lua/luci/view/header_login.htm +rm -Rf /var/luci-modulecache +rm -Rf /var/luci-indexcache +exit 0 diff --git a/rooter/0routerspecfic/rbsxtr/files/usr/lib/rooter/modem-led.sh b/rooter/0routerspecfic/rbsxtr/files/usr/lib/rooter/modem-led.sh new file mode 100644 index 0000000..c331a5c --- /dev/null +++ b/rooter/0routerspecfic/rbsxtr/files/usr/lib/rooter/modem-led.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +log() { + logger -t "modem-led " "$@" +} + +CURRMODEM=$1 +COMMD=$2 + + case $COMMD in + "0" ) + echo none > /sys/class/leds/green:lte/trigger + echo 0 > /sys/class/leds/green:lte/brightness + ;; + "1" ) + echo timer > /sys/class/leds/green:lte/trigger + echo 500 > /sys/class/leds/green:lte/delay_on + echo 500 > /sys/class/leds/green:lte/delay_off + ;; + "2" ) + echo timer > /sys/class/leds/green:lte/trigger + echo 200 > /sys/class/leds/green:lte/delay_on + echo 200 > /sys/class/leds/green:lte/delay_off + ;; + "3" ) + echo timer > /sys/class/leds/green:lte/trigger + echo 1000 > /sys/class/leds/green:lte/delay_on + echo 0 > /sys/class/leds/green:lte/delay_off + ;; + "4" ) + echo none > /sys/class/leds/green:lte/trigger + echo 1 > /sys/class/leds/green:lte/brightness + ;; + esac diff --git a/rooter/0routerspecfic/rbsxtr/files/www/luci-static/background/main_bg.jpg b/rooter/0routerspecfic/rbsxtr/files/www/luci-static/background/main_bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd55ca068ee5bc759e52460f095a3f9dc43dbc55 GIT binary patch literal 34809 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

                          D8@6GORjnT4t+;t)u&K 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 /sys/class/gpio/export + echo out > /sys/class/gpio/gpio${gpio}/direction + echo 1 > /sys/class/gpio/gpio${gpio}/value + log "Turn on PCie Power" +} diff --git a/rooter/0routerspecfic/vpnpolicy/Makefile b/rooter/0routerspecfic/vpnpolicy/Makefile new file mode 100644 index 0000000..5d240b2 --- /dev/null +++ b/rooter/0routerspecfic/vpnpolicy/Makefile @@ -0,0 +1,31 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=vpnpolicy +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/vpnpolicy + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + DEPENDS:=+vpn-policy-routing +luci-app-vpn-policy-routing \ + +ipset +resolveip +ip +kmod-ipt-ipset +iptables +dnsmasq-full + TITLE:=Install scripts for VPN Policy + PKGARCH:=all +endef + +define Package/vpnpolicy/description + Helper scripts to install scripts for VPN Policy +endef + + +define Build/Compile +endef + +$(eval $(call BuildPackage,vpnpolicy)) diff --git a/rooter/0routerspecfic/we826/Makefile b/rooter/0routerspecfic/we826/Makefile new file mode 100644 index 0000000..0c4c68d --- /dev/null +++ b/rooter/0routerspecfic/we826/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=we826 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/we826 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for WE826 Watchdog + PKGARCH:=all +endef + +define Package/we826/description + Helper scripts to install scripts for WE826 Watchdog +endef + + +define Build/Compile +endef + +define Package/we826/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,we826)) diff --git a/rooter/0routerspecfic/we826/files/etc/init.d/wd-init b/rooter/0routerspecfic/we826/files/etc/init.d/wd-init new file mode 100644 index 0000000..baf6d77 --- /dev/null +++ b/rooter/0routerspecfic/we826/files/etc/init.d/wd-init @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 OpenWrt.org + +START=50 +USE_PROCD=1 + +log() { + logger -t "usb-modeswitch" "$@" +} + +start_service() +{ + /usr/lib/custom/watchdog.sh & +} diff --git a/rooter/0routerspecfic/we826/files/usr/lib/custom/watchdog.sh b/rooter/0routerspecfic/we826/files/usr/lib/custom/watchdog.sh new file mode 100644 index 0000000..bf0afe6 --- /dev/null +++ b/rooter/0routerspecfic/we826/files/usr/lib/custom/watchdog.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +#for example WE825-Q watchdog gpio is 2 +# WE826 is 11 +wd_gpio="11" + +echo $wd_gpio > /sys/class/gpio/export +echo out > /sys/class/gpio/gpio$wd_gpio/direction +echo 14 > /sys/class/gpio/export +echo out > /sys/class/gpio/gpio14/direction +echo 255 >/sys/class/gpio/gpio14/value + +while [ 1 ] +do + echo 255 >/sys/class/gpio/gpio$wd_gpio/value + sleep 1 + echo 0 >/sys/class/gpio/gpio$wd_gpio/value + sleep 1 +done diff --git a/rooter/0routerspecfic/we826q/Makefile b/rooter/0routerspecfic/we826q/Makefile new file mode 100644 index 0000000..36779cd --- /dev/null +++ b/rooter/0routerspecfic/we826q/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=we826q +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/we826q + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for WE826-Q + PKGARCH:=all +endef + +define Package/we826q/description + Helper scripts to install scripts for WE826-Q +endef + + +define Build/Compile +endef + +define Package/we826q/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,we826q)) diff --git a/rooter/0routerspecfic/we826q/files/etc/init.d/wd-init b/rooter/0routerspecfic/we826q/files/etc/init.d/wd-init new file mode 100644 index 0000000..fde562a --- /dev/null +++ b/rooter/0routerspecfic/we826q/files/etc/init.d/wd-init @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 OpenWrt.org + +START=20 +USE_PROCD=1 + +log() { + logger -t "usb-modeswitch" "$@" +} + +start_service() +{ + /usr/lib/custom/watchdog.sh & +} diff --git a/rooter/0routerspecfic/we826q/files/usr/lib/custom/watchdog.sh b/rooter/0routerspecfic/we826q/files/usr/lib/custom/watchdog.sh new file mode 100644 index 0000000..281cd4a --- /dev/null +++ b/rooter/0routerspecfic/we826q/files/usr/lib/custom/watchdog.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +#for example WE825-Q watchdog gpio is 2 +wd_gpio="2" + +echo $wd_gpio > /sys/class/gpio/export +echo out > /sys/class/gpio/gpio$wd_gpio/direction + +while [ 1 ] +do + echo 1 >/sys/class/gpio/gpio$wd_gpio/value + sleep 1 + echo 0 >/sys/class/gpio/gpio$wd_gpio/value + sleep 1 + + echo 1 >/sys/class/gpio/gpio$wd_gpio/value + sleep 1 + echo 0 >/sys/class/gpio/gpio$wd_gpio/value + sleep 1 + + echo 1 >/sys/class/gpio/gpio$wd_gpio/value + sleep 1 + echo 0 >/sys/class/gpio/gpio$wd_gpio/value + sleep 1 +done diff --git a/rooter/0routerspecfic/wg1602/Makefile b/rooter/0routerspecfic/wg1602/Makefile new file mode 100644 index 0000000..bc608a7 --- /dev/null +++ b/rooter/0routerspecfic/wg1602/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=wg1602 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/wg1602 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + DEPENDS:=+kmod-mt7615e +kmod-mt76 +kmod-mt7603 +kmod-mt7615-firmware \ + +kmod-mt7615e +kmod-mt7663-firmware-ap +kmod-mt7663-firmware-sta \ + +kmod-mt76x2 + TITLE:=Install scripts for WG1602 + PKGARCH:=all +endef + +define Package/wg1602/description + Helper scripts to install scripts for WG1602 +endef + + +define Build/Compile +endef + +define Package/wg1602/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,wg1602)) diff --git a/rooter/0routerspecfic/wg1602/files/etc/init.d/sw-init b/rooter/0routerspecfic/wg1602/files/etc/init.d/sw-init new file mode 100644 index 0000000..552a708 --- /dev/null +++ b/rooter/0routerspecfic/wg1602/files/etc/init.d/sw-init @@ -0,0 +1,15 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 OpenWrt.org + +START=50 +USE_PROCD=1 + +log() { + logger -t "WatchDog" "$@" +} + +start_service() +{ + log "WG1602 USB Hub switch to USB3.0 infterface" + echo 0 > /sys/class/gpio/ext-usb/value +} diff --git a/rooter/0routerspecfic/wg1602/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/wg1602/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..11a7fde --- /dev/null +++ b/rooter/0routerspecfic/wg1602/files/usr/lib/rooter/special.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +LED=0 +SM=$(uci get system.4G1) +if [ -z $SM ]; then + uci set system.4G1=led + uci set system.4G1.name="4G1" + uci set system.4G1.sysfs="green:4g1" + uci set system.4G1.trigger="netdev" + uci set system.4G1.dev="wwan0" + uci set system.4G1.mode="link tx rx" + LED=1 +fi +SM=$(uci get system.4G2) +if [ -z $SM ]; then + uci set system.4G2=led + uci set system.4G2.name="4G2" + uci set system.4G2.sysfs="green:4g2" + uci set system.4G2.trigger="netdev" + uci set system.4G2.dev="wwan1" + uci set system.4G2.mode="link tx rx" + LED=1 +fi + +if [ $LED -eq 1 ]; then + uci commit system + /etc/init.d/led restart +fi diff --git a/rooter/0routerspecfic/wg1608/Makefile b/rooter/0routerspecfic/wg1608/Makefile new file mode 100644 index 0000000..0e5ab8a --- /dev/null +++ b/rooter/0routerspecfic/wg1608/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=wg1608 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/wg1608 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + DEPENDS:=+kmod-mt7615e +kmod-mt76 +kmod-mt7603 +kmod-mt7615-firmware \ + +kmod-mt7615e +kmod-mt7663-firmware-ap +kmod-mt7663-firmware-sta \ + +kmod-mt76x2 + TITLE:=Install scripts for WG1608 + PKGARCH:=all +endef + +define Package/wg1608/description + Helper scripts to install scripts for WG1608 +endef + + +define Build/Compile +endef + +define Package/wg1608/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,wg1608)) diff --git a/rooter/0routerspecfic/wg1608/files/etc/init.d/wd-init b/rooter/0routerspecfic/wg1608/files/etc/init.d/wd-init new file mode 100644 index 0000000..465976c --- /dev/null +++ b/rooter/0routerspecfic/wg1608/files/etc/init.d/wd-init @@ -0,0 +1,15 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 OpenWrt.org + +START=50 +USE_PROCD=1 + +log() { + logger -t "WatchDog" "$@" +} + +start_service() +{ + /usr/lib/custom/watchdog.sh & + log "Start watchdog" +} diff --git a/rooter/0routerspecfic/wg1608/files/usr/lib/custom/watchdog.sh b/rooter/0routerspecfic/wg1608/files/usr/lib/custom/watchdog.sh new file mode 100644 index 0000000..befbcd7 --- /dev/null +++ b/rooter/0routerspecfic/wg1608/files/usr/lib/custom/watchdog.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +dis=493 +echo $dis > /sys/class/gpio/export +echo out > /sys/class/gpio/gpio$dis/direction +echo 255 >/sys/class/gpio/gpio$dis/value + +echo none > /sys/class/leds/watchdog/trigger +while [ 1 ] +do + echo 1 >/sys/class/leds/watchdog/brightness + sleep 1 + echo 0 >/sys/class/leds/watchdog/brightness + sleep 1 + echo 1 >/sys/class/leds/watchdog/brightness + sleep 1 + echo 0 >/sys/class/leds/watchdog/brightness + sleep 1 + echo 1 >/sys/class/leds/watchdog/brightness + sleep 1 + echo 0 >/sys/class/leds/watchdog/brightness + sleep 5 +done diff --git a/rooter/0routerspecfic/wg1608/files/usr/lib/rooter/modem-led.sh b/rooter/0routerspecfic/wg1608/files/usr/lib/rooter/modem-led.sh new file mode 100644 index 0000000..25b0fa1 --- /dev/null +++ b/rooter/0routerspecfic/wg1608/files/usr/lib/rooter/modem-led.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +log() { + logger -t "modem-led " "$@" +} + +CURRMODEM=$1 +COMMD=$2 + + case $COMMD in + "0" ) + echo none > /sys/class/leds/green:globe/trigger + echo 0 > /sys/class/leds/green:globe/brightness + echo none > /sys/class/leds/green:signal/trigger + echo 0 > /sys/class/leds/green:signal/brightness + ;; + "1" ) + echo timer > /sys/class/leds/green:globe/trigger + echo 500 > /sys/class/leds/green:globe/delay_on + echo 500 > /sys/class/leds/green:globe/delay_off + ;; + "2" ) + echo timer > /sys/class/leds/green:globe/trigger + echo 200 > /sys/class/leds/green:globe/delay_on + echo 200 > /sys/class/leds/green:globe/delay_off + ;; + "3" ) + echo timer > /sys/class/leds/green:globe/trigger + echo 1000 > /sys/class/leds/green:globe/delay_on + echo 0 > /sys/class/leds/green:globe/delay_off + ;; + "4" ) + echo none > /sys/class/leds/green:globe/trigger + echo 1 > /sys/class/leds/green:globe/brightness + sig2=$3 + echo timer > /sys/class/leds/green:signal/trigger + if [ $sig2 -lt 18 -a $sig2 -gt 0 ] 2>/dev/null;then + echo 500 > /sys/class/leds/green:signal/delay_on + echo 500 > /sys/class/leds/green:signal/delay_off + elif [ $sig2 -ge 18 -a $sig2 -lt 31 ] 2>/dev/null;then + echo 150 > /sys/class/leds/green:signal/delay_on + echo 150 > /sys/class/leds/green:signal/delay_off + elif [ $sig2 -eq 31 ] 2>/dev/null;then + echo 0 > /sys/class/leds/green:signal/delay_on + echo 1000 > /sys/class/leds/green:signal/delay_off + else + echo 950 > /sys/class/leds/green:signal/delay_on + echo 950 > /sys/class/leds/green:signal/delay_off + fi + ;; + esac diff --git a/rooter/0routerspecfic/wg1608/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/wg1608/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..92f36d5 --- /dev/null +++ b/rooter/0routerspecfic/wg1608/files/usr/lib/rooter/special.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +LED=0 +SM=$(uci get system.wifi) +if [ -z $SM ]; then + uci set system.wifi=led + uci set system.wifi.name="5Ghzwifi" + uci set system.wifi.sysfs="wifi" + uci set system.wifi.trigger="netdev" + uci set system.wifi.dev="wlan1" + uci set system.wifi.mode="link tx rx" + uci commit system + /etc/init.d/led restart +fi + diff --git a/rooter/0routerspecfic/wg209/Makefile b/rooter/0routerspecfic/wg209/Makefile new file mode 100644 index 0000000..34852dd --- /dev/null +++ b/rooter/0routerspecfic/wg209/Makefile @@ -0,0 +1,33 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=wg209 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/wg209 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for WG209 + PKGARCH:=all +endef + +define Package/wg209/description + Helper scripts to install scripts for WG209 +endef + + +define Build/Compile +endef + +define Package/wg209/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,wg209)) diff --git a/rooter/0routerspecfic/wg209/files/usr/lib/rooter/modem-led.sh b/rooter/0routerspecfic/wg209/files/usr/lib/rooter/modem-led.sh new file mode 100644 index 0000000..9cdace0 --- /dev/null +++ b/rooter/0routerspecfic/wg209/files/usr/lib/rooter/modem-led.sh @@ -0,0 +1,76 @@ +#!/bin/sh + +log() { + logger -t "modem-led " "$@" +} + +CURRMODEM=$1 +COMMD=$2 + + case $COMMD in + "0" ) + echo none > /sys/class/leds/green:signal1/trigger + echo 0 > /sys/class/leds/green:signal1/brightness + echo none > /sys/class/leds/green:signal2/trigger + echo 0 > /sys/class/leds/green:signal2/brightness + echo none > /sys/class/leds/green:signal3/trigger + echo 0 > /sys/class/leds/green:signal3/brightness + echo none > /sys/class/leds/green:internet/trigger + echo 0 > /sys/class/leds/green:internet/brightness + ;; + "1" ) + echo timer > /sys/class/leds/green:internet/trigger + echo 500 > /sys/class/leds/green:internet/delay_on + echo 500 > /sys/class/leds/green:internet/delay_off + ;; + "2" ) + echo timer > /sys/class/leds/green:internet/trigger + echo 200 > /sys/class/leds/green:internet/delay_on + echo 200 > /sys/class/leds/green:internet/delay_off + ;; + "3" ) + echo timer > /sys/class/leds/green:internet/trigger + echo 1000 > /sys/class/leds/green:internet/delay_on + echo 0 > /sys/class/leds/green:internet/delay_off + ;; + "4" ) + sig2=$3 + if [ $sig2 -lt 8 -a $sig2 -gt 0 ] 2>/dev/null;then + echo none > /sys/class/leds/green:internet/trigger + echo 1 > /sys/class/leds/green:internet/brightness + echo none > /sys/class/leds/green:signal3/trigger + echo 0 > /sys/class/leds/green:signal3/brightness + echo none > /sys/class/leds/green:signal2/trigger + echo 0 > /sys/class/leds/green:signal2/brightness + echo none > /sys/class/leds/green:signal1/trigger + echo 0 > /sys/class/leds/green:signal1/brightness + elif [ $sig2 -ge 8 -a $sig2 -lt 16 ] 2>/dev/null;then + echo none > /sys/class/leds/green:internet/trigger + echo 1 > /sys/class/leds/green:internet/brightness + echo none > /sys/class/leds/green:signal3/trigger + echo 1 > /sys/class/leds/green:signal3/brightness + echo none > /sys/class/leds/green:signal2/trigger + echo 0 > /sys/class/leds/green:signal2/brightness + echo none > /sys/class/leds/green:signal1/trigger + echo 0 > /sys/class/leds/green:signal1/brightness + elif [ $sig2 -ge 16 -a $sig2 -lt 24 ] 2>/dev/null;then + echo none > /sys/class/leds/green:internet/trigger + echo 1 > /sys/class/leds/green:internet/brightness + echo none > /sys/class/leds/green:signal3/trigger + echo 1 > /sys/class/leds/green:signal3/brightness + echo none > /sys/class/leds/green:signal2/trigger + echo 1 > /sys/class/leds/green:signal2/brightness + echo none > /sys/class/leds/green:signal1/trigger + echo 0 > /sys/class/leds/green:signal1/brightness + elif [ $sig2 -ge 24 ] 2>/dev/null;then + echo none > /sys/class/leds/green:internet/trigger + echo 1 > /sys/class/leds/green:internet/brightness + echo none > /sys/class/leds/green:signal3/trigger + echo 1 > /sys/class/leds/green:signal3/brightness + echo none > /sys/class/leds/green:signal2/trigger + echo 1 > /sys/class/leds/green:signal2/brightness + echo none > /sys/class/leds/green:signal1/trigger + echo 1 > /sys/class/leds/green:signal1/brightness + fi + ;; + esac diff --git a/rooter/0routerspecfic/wg259/Makefile b/rooter/0routerspecfic/wg259/Makefile new file mode 100644 index 0000000..c0a41ae --- /dev/null +++ b/rooter/0routerspecfic/wg259/Makefile @@ -0,0 +1,34 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=wg259 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/wg259 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + DEPENDS:=+kmod-mt76 +kmod-mt7603 +kmod-mt76x2 + TITLE:=Install scripts for WG259 + PKGARCH:=all +endef + +define Package/wg259/description + Helper scripts to install scripts for WG259 +endef + + +define Build/Compile +endef + +define Package/wg259/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,wg259)) diff --git a/rooter/0routerspecfic/wg259/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/wg259/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..94ee31a --- /dev/null +++ b/rooter/0routerspecfic/wg259/files/usr/lib/rooter/special.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +SM=$(uci get system.4g5g) +if [ -z $SM ]; then + uci set system.4g5g=led + uci set system.4g5g.name="4G5G" + uci set system.4g5g.sysfs="green:usb" + uci set system.4g5g.trigger="netdev" + uci set system.4g5g.dev="wwan0" + uci set system.4g5g.mode="link tx rx" + uci set system.4g5g.default='0' + + uci set system.sys=led + uci set system.sys.name="SYS" + uci set system.sys.sysfs="green:status" + uci set system.sys.trigger="netdev" + uci set system.sys.dev="br-lan" + uci set system.sys.mode="link tx rx" + uci set system.sys.default='0' + + uci commit system + /etc/init.d/led restart +fi diff --git a/rooter/0routerspecfic/wg3526/Makefile b/rooter/0routerspecfic/wg3526/Makefile new file mode 100644 index 0000000..8cb384e --- /dev/null +++ b/rooter/0routerspecfic/wg3526/Makefile @@ -0,0 +1,33 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=wg3526 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/wg3526 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for wg3526 + PKGARCH:=all +endef + +define Package/wg3526/description + Helper scripts to install scripts for wg3526 +endef + + +define Build/Compile +endef + +define Package/wg3526/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,wg3526)) diff --git a/rooter/0routerspecfic/wg3526/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/wg3526/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..e27a0b3 --- /dev/null +++ b/rooter/0routerspecfic/wg3526/files/usr/lib/rooter/special.sh @@ -0,0 +1,19 @@ +#!/bin/sh + + +echo none > /sys/class/leds/green:status/trigger +echo 0 > /sys/class/leds/green:status/brightness + +SM=$(uci get system.4g5g) +if [ -z $SM ]; then + uci set system.4g5g=led + uci set system.4g5g.name="4G5G" + uci set system.4g5g.sysfs="green:status" + uci set system.4g5g.trigger="netdev" + uci set system.4g5g.dev="wwan0" + uci set system.4g5g.mode="link tx rx" + uci set system.4g5g.default='0' + + uci commit system + /etc/init.d/led restart +fi \ No newline at end of file diff --git a/rooter/0routerspecfic/wg827/Makefile b/rooter/0routerspecfic/wg827/Makefile new file mode 100644 index 0000000..c8a419f --- /dev/null +++ b/rooter/0routerspecfic/wg827/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=wg827 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/wg827 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + DEPENDS:=+kmod-mt7615e +kmod-mt76 +kmod-mt7603 +kmod-mt7615-firmware \ + +kmod-mt7615e +kmod-mt7663-firmware-ap +kmod-mt7663-firmware-sta \ + +kmod-mt76x2 + TITLE:=Install scripts for WG827 + PKGARCH:=all +endef + +define Package/wg827/description + Helper scripts to install scripts for WG827 +endef + + +define Build/Compile +endef + +define Package/wg827/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,wg827)) diff --git a/rooter/0routerspecfic/wg827/files/usr/lib/rooter/modem-led.sh b/rooter/0routerspecfic/wg827/files/usr/lib/rooter/modem-led.sh new file mode 100644 index 0000000..cdf5b4c --- /dev/null +++ b/rooter/0routerspecfic/wg827/files/usr/lib/rooter/modem-led.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +log() { + logger -t "modem-led " "$@" +} + +CURRMODEM=$1 +COMMD=$2 + + case $COMMD in + "0" ) + echo none > /sys/class/leds/rgb:blue/trigger + echo 0 > /sys/class/leds/rgb:blue/brightness + echo none > /sys/class/leds/rgb:green/trigger + echo 1 > /sys/class/leds/rgb:green/brightness + ;; + "1" ) + echo timer > /sys/class/leds/rgb:blue/trigger + echo 500 > /sys/class/leds/rgb:blue/delay_on + echo 500 > /sys/class/leds/rgb:blue/delay_off + ;; + "2" ) + echo timer > /sys/class/leds/rgb:blue/trigger + echo 200 > /sys/class/leds/rgb:blue/delay_on + echo 200 > /sys/class/leds/rgb:blue/delay_off + ;; + "3" ) + echo timer > /sys/class/leds/rgb:blue/trigger + echo 1000 > /sys/class/leds/rgb:blue/delay_on + echo 0 > /sys/class/leds/rgb:blue/delay_off + ;; + "4" ) + echo none > /sys/class/leds/rgb:blue/trigger + echo 1 > /sys/class/leds/rgb:blue/brightness + echo none > /sys/class/leds/rgb:green/trigger + echo 0 > /sys/class/leds/rgb:green/brightness + ;; + esac diff --git a/rooter/0routerspecfic/wrt1900/Makefile b/rooter/0routerspecfic/wrt1900/Makefile new file mode 100644 index 0000000..843e6a6 --- /dev/null +++ b/rooter/0routerspecfic/wrt1900/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=wrt1900 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/wrt1900 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for WRT1900 + PKGARCH:=all +endef + +define Package/wrt1900/description + Helper scripts to install scripts for WRT1900 +endef + + +define Build/Compile +endef + +define Package/wrt1900/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,wrt1900)) diff --git a/rooter/0routerspecfic/wrt1900/files/etc/init.d/amsdu b/rooter/0routerspecfic/wrt1900/files/etc/init.d/amsdu new file mode 100644 index 0000000..aa39594 --- /dev/null +++ b/rooter/0routerspecfic/wrt1900/files/etc/init.d/amsdu @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 OpenWrt.org + +START=70 + +log() { + logger -t "AMSDU" "$@" +} + +start_service() +{ + echo 0 > /sys/kernel/debug/ieee80211/phy0/mwlwifi/tx_amsdu + echo 0 > /sys/kernel/debug/ieee80211/phy1/mwlwifi/tx_amsdu +} diff --git a/rooter/0routerspecfic/x750/Makefile b/rooter/0routerspecfic/x750/Makefile new file mode 100644 index 0000000..ad8caca --- /dev/null +++ b/rooter/0routerspecfic/x750/Makefile @@ -0,0 +1,33 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=x750 +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/x750 + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Router Specific + TITLE:=Install scripts for x750 + PKGARCH:=all +endef + +define Package/x750/description + Helper scripts to install scripts for x750 +endef + + +define Build/Compile +endef + +define Package/x750/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,x750)) diff --git a/rooter/0routerspecfic/x750/files/usr/lib/rooter/special.sh b/rooter/0routerspecfic/x750/files/usr/lib/rooter/special.sh new file mode 100644 index 0000000..9787a19 --- /dev/null +++ b/rooter/0routerspecfic/x750/files/usr/lib/rooter/special.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +SM=$(uci get system.4g5g) +if [ -z $SM ]; then + uci set system.4g5g=led + uci set system.4g5g.name="4G5G" + uci set system.4g5g.sysfs="green:4g" + uci set system.4g5g.trigger="netdev" + uci set system.4g5g.dev="wwan0" + uci set system.4g5g.mode="link tx rx" + uci set system.4g5g.default='0' + + uci commit system + /etc/init.d/led restart +fi + +uci set system.gpio2=gpio_switch +uci set system.gpio2.name='gpio2' +uci set system.gpio2.gpio_pin='2' +uci set system.gpio2.value='0' +uci commit system +/etc/init.d/system restart + diff --git a/rooter/0splash/ext-splash/Makefile b/rooter/0splash/ext-splash/Makefile new file mode 100644 index 0000000..8372994 --- /dev/null +++ b/rooter/0splash/ext-splash/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-splash +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-splash + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Splash Screens + TITLE:=Added scripts for Login display + PKGARCH:=all +endef + +define Package/ext-splash/description + Added scripts for Login display +endef + + +define Build/Compile +endef + +define Package/ext-splash/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-splash)) diff --git a/rooter/0splash/ext-splash/files/etc/config/iframe b/rooter/0splash/ext-splash/files/etc/config/iframe new file mode 100644 index 0000000..a97bc1d --- /dev/null +++ b/rooter/0splash/ext-splash/files/etc/config/iframe @@ -0,0 +1,17 @@ + +config iframe 'iframe' + option splashpage '0' + option splashtitle 'ROOter' + option url 'www.ofmodemsandmen.com' + option dual '0' + option speed '0' + option band '0' + +config login 'login' + option logframe '0' + option logtype '3' + option logimage 'open.png' + option logimageheight '300' + option logimagewidth '300' + option logimagepos 'absmiddle' + diff --git a/rooter/0splash/ext-splash/files/etc/init.d/iframeint b/rooter/0splash/ext-splash/files/etc/init.d/iframeint new file mode 100644 index 0000000..79f6de6 --- /dev/null +++ b/rooter/0splash/ext-splash/files/etc/init.d/iframeint @@ -0,0 +1,18 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 OpenWrt.org + +START=60 +USE_PROCD=1 + +log() { + logger -t "iframe" "$@" +} + +start_service() +{ + if [ ! -d /tmp/www ]; then + mkdir -p /tmp/www + fi + /usr/lib/iframe/create.sh & + /usr/lib/iframe/status.sh & +} diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/band.html b/rooter/0splash/ext-splash/files/usr/lib/iframe/band.html new file mode 100644 index 0000000..9db882d --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/band.html @@ -0,0 +1 @@ +

                          \ No newline at end of file diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/bwdays.sh b/rooter/0splash/ext-splash/files/usr/lib/iframe/bwdays.sh new file mode 100644 index 0000000..1c5a776 --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/bwdays.sh @@ -0,0 +1,109 @@ +#!/bin/sh +. /lib/functions.sh + +genline() { + MONLIST=$MONLIST"" + t1="
                          $START
                          " + t2="
                          $updata
                          " + t3="
                          $downdata
                          " + t4="
                          $totaldata
                          " + MONLIST=$MONLIST$t1$t2$t3$t4"" +} + +bwdata() { + START="-" + END="-" + header=0 + while IFS= read -r line; do + if [ $header -eq 0 ]; then + days=$line + read -r line + DOWN=$line + read -r line + UP=$line + read -r line + TOTAL=$line + read -r line + line=$(echo $line" " | tr "|" ",") + END=$(echo $line | cut -d, -f1) + START=$END + updata=$(echo $line | cut -d, -f2) + downdata=$(echo $line | cut -d, -f3) + totaldata=$(echo $line | cut -d, -f4) + genline + read -r line + header=1 + if [ -z "$line" ]; then + break + fi + fi + line=$(echo $line" " | tr "|" ",") + START=$(echo $line | cut -d, -f1) + updata=$(echo $line | cut -d, -f2) + downdata=$(echo $line | cut -d, -f3) + totaldata=$(echo $line | cut -d, -f4) + genline + + done < /usr/lib/bwmon/data/monthly.data +} + +currdata() { + while IFS= read -r line; do + if [ $line = '0' ]; then + break + else + cdays=$line + read -r line + read -r line + ctused=$line + read -r line + read -r line + ctdwn=$line + read -r line + read -r line + ctup=$line + read -r line + read -r line + cproject=$line + break + fi + done < /tmp/bwdata +} + + STEMP="/tmp/www/dtemp.html" + STATUS="/usr/lib/iframe/bwtemplate.html" + IFSTATUS="/tmp/www/daylist.html" + + MONLIST="" + + rm -f $STEMP + cp $STATUS $STEMP + if [ -e /usr/lib/bwmon/data/monthly.data ]; then + #MONLIST="" + bwdata + MONLIST=$MONLIST"
                          " + else + START="-" + END="-" + TOTAL="-" + DOWN="-" + UP="-" + fi + + currdata + + sed -i -e "s!#START#!$START!g" $STEMP + sed -i -e "s!#END#!$END!g" $STEMP + sed -i -e "s!#TOTAL#!$TOTAL!g" $STEMP + sed -i -e "s!#DOWN#!$DOWN!g" $STEMP + sed -i -e "s!#UP#!$UP!g" $STEMP + sed -i -e "s!#MONLIST#!$MONLIST!g" $STEMP + + sed -i -e "s!#CDAYS#!$cdays!g" $STEMP + sed -i -e "s!#CTOTAL#!$ctused!g" $STEMP + sed -i -e "s!#CDOWN#!$ctdwn!g" $STEMP + sed -i -e "s!#CUP#!$ctup!g" $STEMP + sed -i -e "s!#PROJECT#!$cproject!g" $STEMP + + mv $STEMP $IFSTATUS + diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/bwtemplate.html b/rooter/0splash/ext-splash/files/usr/lib/iframe/bwtemplate.html new file mode 100644 index 0000000..81b6ec9 --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/bwtemplate.html @@ -0,0 +1,85 @@ + + + + + + + + + +

                          Current Month's Bandwidth Usage

                          +
                          +
                          +
                          +
                          Days
                          + #CDAYS# +
                          +
                          +
                          Total Amount Used
                          + #CTOTAL# +
                          +
                          +
                          +
                          +
                          Downloaded
                          + #CDOWN# +
                          +
                          +
                          Uploaded
                          + #CUP# +
                          +
                          +
                          Projected Amount
                          + #PROJECT# +
                          +
                          +
                          + +

                          Last 30 Day Bandwidth Usage

                          + + +
                          +
                          +
                          +
                          Starting Date
                          + #START# +
                          +
                          +
                          Ending Date
                          + #END# +
                          +
                          +
                          +
                          +
                          Total
                          + #TOTAL# +
                          +
                          +
                          Download
                          + #DOWN# +
                          +
                          +
                          Upload
                          + #UP# +
                          +
                          +
                          + +
                          + + + + + + + + + #MONLIST# + + + diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/create.sh b/rooter/0splash/ext-splash/files/usr/lib/iframe/create.sh new file mode 100644 index 0000000..5a292e5 --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/create.sh @@ -0,0 +1,31 @@ +#!/bin/sh +. /lib/functions.sh + +bwdata() { + result=`ps | grep -i "create_data.lua" | grep -v "grep" | wc -l` + if [ $result -lt 1 ]; then + lua /usr/lib/bwmon/create_data.lua + fi + while [ true ] + do + if [ -e /tmp/bwdata ]; then + break + fi + sleep 1 + done +} + +bwdata +/usr/lib/iframe/update.sh +logtype=$(uci -q get iframe.login.logtype) +if [ $logtype = "1" ]; then + sleep 300 + while [ true ] + do + result=`ps | grep -i "update.sh" | grep -v "grep" | wc -l` + if [ $result -lt 1 ]; then + /usr/lib/iframe/update.sh + fi + sleep 300 + done +fi \ No newline at end of file diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/daylist.html b/rooter/0splash/ext-splash/files/usr/lib/iframe/daylist.html new file mode 100644 index 0000000..ba5170d --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/daylist.html @@ -0,0 +1,85 @@ + + + + + + + + + +

                          Current Month's Bandwidth Usage

                          +
                          +
                          +
                          +
                          Days
                          + 10 +
                          +
                          +
                          Total Amount Used
                          + 451.39 MB +
                          +
                          +
                          +
                          +
                          Downloaded
                          + 409.57 MB +
                          +
                          +
                          Uploaded
                          + 41.82 MB +
                          +
                          +
                          Projected Amount
                          + 1.35 GB +
                          +
                          +
                          + +

                          Last 30 Day Bandwidth Usage

                          + + +
                          +
                          +
                          +
                          Starting Date
                          + 2022-01-03 +
                          +
                          +
                          Ending Date
                          + 2022-01-15 +
                          +
                          +
                          +
                          +
                          Total
                          + 360.05 MB +
                          +
                          +
                          Download
                          + 322.79 MB +
                          +
                          +
                          Upload
                          + 37.25 MB +
                          +
                          +
                          + +
                          +
                          DATE
                          DOWN
                          UP
                          TOTAL
                          + + + + + + + +
                          DATE
                          DOWN
                          UP
                          TOTAL
                          2022-01-15
                          0.00 K
                          0.00 K
                          0.00 K
                          2022-01-14
                          0.00 K
                          0.00 K
                          0.00 K
                          2022-01-13
                          41.87 MB
                          1.71 MB
                          43.58 MB
                          2022-01-12
                          0.00 K
                          0.00 K
                          0.00 K
                          2022-01-07
                          18.56 MB
                          5.24 MB
                          23.80 MB
                          2022-01-06
                          175.59 MB
                          25.72 MB
                          201.32 MB
                          2022-01-04
                          56.19 MB
                          3.59 MB
                          59.78 MB
                          2022-01-03
                          30.58 MB
                          986.00 K
                          31.57 MB
                          +
                          + + diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/iframe.html b/rooter/0splash/ext-splash/files/usr/lib/iframe/iframe.html new file mode 100644 index 0000000..aa47d93 --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/iframe.html @@ -0,0 +1,41 @@ + + + + + + + + + +

                          #TITLE#

                          + +
                          +
                          +
                          +
                          Reporting Period (Days)
                          + #DAYS# +
                          +
                          +
                          +
                          +
                          Total Bandwidth Used
                          + #TOTAL# +
                          +
                          +
                          Projected Use
                          + #PROJ# +
                          +
                          +
                          +
                          +
                          Total Downloaded
                          + #DOWN# +
                          +
                          +
                          Total Uploaded
                          + #UP# +
                          +
                          +
                          + + diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/image.html b/rooter/0splash/ext-splash/files/usr/lib/iframe/image.html new file mode 100644 index 0000000..a7b9893 --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/image.html @@ -0,0 +1,11 @@ + + + + + + + +

                           

                          +

                          + + diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/modem2.html b/rooter/0splash/ext-splash/files/usr/lib/iframe/modem2.html new file mode 100644 index 0000000..5957a8b --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/modem2.html @@ -0,0 +1 @@ +

                          Modem 2

                          Strength (%)
                          #PER#
                          CSQ
                          #CSQ#
                          RSSI (dBm)
                          #RSSI#
                          RSCP (dBm) RSRP
                          #RSCP#
                          ECIO (dB) RSRQ
                          #RSRQ#
                          SINR (dB)
                          #SINR#

                          Network

                          Mode
                          #MODE#
                          MCC
                          #MCC#
                          MNC
                          #MNC#
                          RNC/eNB ID
                          #RNC# #RNCN#
                          LAC
                          #LAC# #LACN#
                          Channel (EARFCN)
                          #CHAN#
                          PCI
                          #CELLID#
                          Bands
                          #BAND#

                          Device

                          Modem
                          #MODEM#
                          Provider
                          #MODEMN#
                          Protocol
                          #PROTO#
                          Port
                          #PORT#
                          Temperature
                          #TEMP#
                          \ No newline at end of file diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/open.html b/rooter/0splash/ext-splash/files/usr/lib/iframe/open.html new file mode 100644 index 0000000..fa7d40d --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/open.html @@ -0,0 +1 @@ +
                          OpenSpeedTest
                          \ No newline at end of file diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/speed.html b/rooter/0splash/ext-splash/files/usr/lib/iframe/speed.html new file mode 100644 index 0000000..0338c71 --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/speed.html @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          OpenSpeedTest

                          + +
                          + +
                          + +
                          + + + + diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/status.html b/rooter/0splash/ext-splash/files/usr/lib/iframe/status.html new file mode 100644 index 0000000..ddb0c69 --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/status.html @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + #TITLEBAR# + #BUTTON# +
                          +

                          Modem 1

                          +
                          +
                          +
                          Strength (%)
                          + #PER# +
                          +
                          +
                          CSQ
                          + #CSQ# +
                          +
                          +
                          RSSI (dBm)
                          + #RSSI# +
                          +
                          +
                          RSCP (dBm) RSRP
                          + #RSCP# +
                          +
                          +
                          ECIO (dB) RSRQ
                          + #RSRQ# +
                          +
                          +
                          SINR (dB)
                          + #SINR# +
                          +
                          + +
                          +

                          Network

                          + +
                          +
                          +
                          Mode
                          + #MODE# +
                          +
                          +
                          MCC
                          + #MCC# +
                          +
                          +
                          MNC
                          + #MNC# +
                          +
                          +
                          RNC/eNB ID
                          + #RNC# #RNCN# +
                          + +
                          +
                          LAC
                          + #LAC# #LACN# +
                          +
                          +
                          Channel (EARFCN)
                          + #CHAN# +
                          +
                          +
                          PCI
                          + #CELLID# +
                          +
                          +
                          Bands
                          + #BAND# +
                          +
                          +
                          +
                          +

                          Device

                          + +
                          +
                          +
                          Router
                          + #ROUTER# +
                          +
                          +
                          Modem
                          + #MODEM# +
                          +
                          +
                          Provider
                          + #PROVIDER# +
                          +
                          +
                          Protocol
                          + #PROTO# +
                          +
                          +
                          Port
                          + #PORT# +
                          +
                          +
                          Temperature
                          + #TEMP# +
                          +
                          +
                          + #MODEM2# +
                          + + + #OPEN# + + #BWMON# + + + diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/status.sh b/rooter/0splash/ext-splash/files/usr/lib/iframe/status.sh new file mode 100644 index 0000000..ed0881b --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/status.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +/usr/lib/rooter/signal/status.sh 1 "No Modem Present" + +while [ true ] +do + result=`ps | grep -i "stupdate.sh" | grep -v "grep" | wc -l` + if [ $result -lt 1 ]; then + /usr/lib/iframe/stupdate.sh + /usr/lib/iframe/bwdays.sh + fi + splash=$(uci -q get iframe.iframe.splashpage) + if [ $splash = "1" ]; then + mv /www/splash_files/check1.gif /www/splash_files/check.gif + ln -s /tmp/www/splash.html /www/splash.html + else + mv /www/splash_files/check.gif /www/splash_files/check1.gif + rm -f /www/splash.html + fi + sleep 10 +done \ No newline at end of file diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/stupdate.sh b/rooter/0splash/ext-splash/files/usr/lib/iframe/stupdate.sh new file mode 100644 index 0000000..e66f255 --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/stupdate.sh @@ -0,0 +1,352 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Status Update" "$@" +} + +levelsper="101,85,70,55,40,25,10,1,0" +namesper="Perfect,Excellent,Good,Medium,Low,Bad,Dead" +levelsrssi="113,119,100,90,70,1,0" +namesrssi="None,Bad,Poor,Medium,High,Perfect" +levelsrscp="140,136,112,100,90,70,50,1,0" +namesrscp='None,None (3G) : Poor (4G),Weak (3G) : Medium (4G),Poor (3G) : Good (4G),Medium (3G) : High (4G),High (3G) :High (4G)' + +level2txt() { + tmp="$1" + key=$2 + front="" + tmp1="$tmp"" " + if [ "$tmp" = "-" ]; then + namev="""--""" + return + fi + if [ $key = "per" ]; then + tmp=$(echo "$tmp" | sed -e "s/%//g") + level=$levelsper + namev=$namesper + fi + if [ $key = "rssi" ]; then + front="-" + tmp=$(echo "$tmp" | sed -e "s/-//g") + tmp=$(echo "$tmp" | sed -e "s/dBm//g") + tmp1="$tmp"" " + level=$levelsrssi + namev=$namesrssi + fi + if [ $key = "rscp" ]; then + front="" + tmp=$(echo "$tmp" | sed -e "s/dBm//g") + tmp=$(echo "$tmp" | sed -e "s/([^)]*)//g") + tmp1="$tmp"" " + tmp=$(echo "$tmp" | sed -e "s/-//g") + tmp=$(echo "$tmp" | tr " " "," | cut -d, -f1 ) + tmp=$(printf %.0f "$tmp") + level=$levelsrscp + namev=$namesrscp + fi + + if [ $key = "single" ]; then + desc="" + tmp=$(echo "$tmp" | sed -e "s/dBm//g") + tmp=$(echo "$tmp" | sed -e "s/dB//g") + if [ $3 != "1" ];then + tmp=$(echo "$tmp" | sed -e "s/-//g") + fi + if [ $3 = "1" -o $3 = "0" ];then + desc="
                          "."
                          " + fi + namev="""$tmp"""$desc + return + fi + + namez=$namev + cindex=1 + nindex=6 + namev="-" + + while [ true ] + do + levelv=$(echo "$level" | cut -d, -f$cindex) + if [ $levelv = "0" ]; then + namev="-" + break + fi + if [ "$tmp" -lt "$levelv" ]; then + namev=$(echo "$namez" | cut -d, -f$nindex) + break + fi + cindex=$((${cindex}+1)) + nindex=$((${nindex}-1)) + done + + css="level_"$nindex + desc="
                          "$namev"
                          " + namev="""$front$tmp1"""$desc +} + +readstatus() { +modd=$1 + while IFS= read -r line; do + port="$line" + read -r line + csq="$line" + read -r line + per="$line" + read -r line + rssi="$line" + read -r line + modem="$line" + read -r line + cops="$line" + read -r line + mode="$line" + read -r line + lac="$line" + read -r line + lacn="$line" + read -r line + cid="$line" + + read -r line + cidn="$line" + read -r line + mcc="$line" + read -r line + mnc="$line" + read -r line + rnc="$line" + read -r line + rncn="$line" + read -r line + down="$line" + read -r line + up="$line" + read -r line + ecio="$line" + read -r line + rscp="$line" + read -r line + ecio1="$line" + + read -r line + rscp1="$line" + read -r line + netmode="$line" + read -r line + cell="$line" + read -r line + modtype="$line" + read -r line + conntype="$line" + read -r line + channel="$line" + read -r line + phone="$line" + read -r line + read -r line + lband="$line" + read -r line + tempur="$line" + + read -r line + proto="$line" + read -r line + pci="$line" + read -r line + sinr="$line" + break + done < /tmp/status$modd.file +} + +bwdata() { + while IFS= read -r line; do + if [ $line = '0' ]; then + nodata="1" + break + else + nodata="0" + days=$line + read -r line + read -r line + tused=$line + read -r line + read -r line + tdwn=$line + read -r line + read -r line + tup=$line + read -r line + read -r line + project=$line + break + fi + done < /tmp/bwdata +} + +splash=$(uci -q get iframe.iframe.splashpage) + +if [ $splash = "1" ]; then + STEMP="/tmp/www/stemp.html" + STATUS="/usr/lib/iframe/status.html" + SPSTATUS="/tmp/www/splash.html" + rm -f $STEMP + cp $STATUS $STEMP + button="
                          " + sed -i -e "s!#BUTTON#!$button!g" $STEMP + sed -i -e "s!#LUCIS#!luci-static/!g" $STEMP + titlebar="" + url=$(uci -q get iframe.iframe.url) + if [ -z $url ]; then + url="www.ofmodemsandmen.com" + fi + titlebar=$(echo "$titlebar" | sed -e "s!#URL#!$url!g") + sed -i -e "s!#TITLEBAR#!$titlebar!g" $STEMP + title=$(uci -q get iframe.iframe.splashtitle) + sed -i -e "s!#TITLE#!$title!g" $STEMP + + readstatus 1 + level2txt "$csq" "single" 0 + sed -i -e "s!#CSQ#!$namev!g" $STEMP + level2txt "$per" "per" + sed -i -e "s!#PER#!$namev!g" $STEMP + level2txt "$rssi" "rssi" + sed -i -e "s!#RSSI#!$namev!g" $STEMP + level2txt "$rscp" "rscp" + sed -i -e "s!#RSCP#!$namev!g" $STEMP + level2txt "$ecio" "single" 1 + sed -i -e "s!#RSRQ#!$namev!g" $STEMP + level2txt "$sinr" "single" 1 + sed -i -e "s!#SINR#!$namev!g" $STEMP + + level2txt "$mode" "single" + sed -i -e "s!#MODE#!$namev!g" $STEMP + level2txt "$mcc" "single" + sed -i -e "s!#MCC#!$namev!g" $STEMP + level2txt "$mnc" "single" + sed -i -e "s!#MNC#!$namev!g" $STEMP + level2txt "$rnc" "single" + sed -i -e "s!#RNC#!$namev!g" $STEMP + level2txt "$rncn" "single" + sed -i -e "s!#RNCN#!$namev!g" $STEMP + level2txt "$lac" "single" + sed -i -e "s!#LAC#!$namev!g" $STEMP + level2txt "$lacn" "single" + sed -i -e "s!#LACN#!$namev!g" $STEMP + level2txt "$pci" "single" + sed -i -e "s!#CELLID#!$namev!g" $STEMP + level2txt "$channel" "single" + sed -i -e "s!#CHAN#!$namev!g" $STEMP + level2txt "$lband" "single" + sed -i -e "s!#BAND#!$namev!g" $STEMP + + if [ -e /etc/custom ]; then + mod="/etc/custom" + else + mod="/tmp/sysinfo/model" + fi + while IFS= read -r line; do + ROUTER=$line + break + done < $mod + level2txt "$ROUTER" "single" + sed -i -e "s!#ROUTER#!$namev!g" $STEMP + level2txt "$modem" "single" + sed -i -e "s!#MODEM#!$namev!g" $STEMP + level2txt "$cops" "single" + namev=$(echo "$namev" | tr -d '&') + sed -i -e "s!#PROVIDER#!$namev!g" $STEMP + level2txt "$proto" "single" + sed -i -e "s!#PROTO#!$namev!g" $STEMP + level2txt "$port" "single" + sed -i -e "s!#PORT#!$namev!g" $STEMP + level2txt "$tempur" "single" + sed -i -e "s!#TEMP#!$namev!g" $STEMP + + dual=$(uci -q get iframe.iframe.dual) + if [ $dual = "1" ]; then + STEMP2="/tmp/www/stemp2.html" + STATUS2="/usr/lib/iframe/modem2.html" + rm -f $STEMP2 + cp $STATUS2 $STEMP2 + + readstatus 2 + level2txt "$csq" "single" 0 + sed -i -e "s!#CSQ#!$namev!g" $STEMP2 + level2txt "$per" "per" + sed -i -e "s!#PER#!$namev!g" $STEMP2 + level2txt "$rssi" "rssi" + sed -i -e "s!#RSSI#!$namev!g" $STEMP2 + level2txt "$rscp" "rscp" + sed -i -e "s!#RSCP#!$namev!g" $STEMP2 + level2txt "$ecio" "single" 1 + sed -i -e "s!#RSRQ#!$namev!g" $STEMP2 + level2txt "$sinr" "single" 1 + sed -i -e "s!#SINR#!$namev!g" $STEMP2 + + level2txt "$mode" "single" + sed -i -e "s!#MODE#!$namev!g" $STEMP2 + level2txt "$mcc" "single" + sed -i -e "s!#MCC#!$namev!g" $STEMP2 + level2txt "$mnc" "single" + sed -i -e "s!#MNC#!$namev!g" $STEMP2 + level2txt "$rnc" "single" + sed -i -e "s!#RNC#!$namev!g" $STEMP2 + level2txt "$rncn" "single" + sed -i -e "s!#RNCN#!$namev!g" $STEMP2 + level2txt "$lac" "single" + sed -i -e "s!#LAC#!$namev!g" $STEMP2 + level2txt "$lacn" "single" + sed -i -e "s!#LACN#!$namev!g" $STEMP2 + level2txt "$pci" "single" + sed -i -e "s!#CELLID#!$namev!g" $STEMP2 + level2txt "$channel" "single" + sed -i -e "s!#CHAN#!$namev!g" $STEMP2 + level2txt "$lband" "single" + sed -i -e "s!#BAND#!$namev!g" $STEMP2 + + level2txt "$modem" "single" + sed -i -e "s!#MODEM#!$namev!g" $STEMP2 + level2txt "$cops" "single" + namev=$(echo "$namev" | tr -d '&') + sed -i -e "s!#MODEMN#!$namev!g" $STEMP2 + level2txt "$proto" "single" + sed -i -e "s!#PROTO#!$namev!g" $STEMP2 + level2txt "$port" "single" + sed -i -e "s!#PORT#!$namev!g" $STEMP2 + level2txt "$tempur" "single" + sed -i -e "s!#TEMP#!$namev!g" $STEMP2 + + MODEM2=$(cat $STEMP2) + sed -i -e "s!#MODEM2#!$MODEM2!g" $STEMP + else + sed -i -e "s!#MODEM2#!!g" $STEMP + fi + + open=$(uci -q get iframe.iframe.speed) + if [ $open = "1" ]; then + STEMP2="/tmp/www/stemp2.html" + STATUS2="/usr/lib/iframe/open.html" + rm -f $STEMP2 + cp $STATUS2 $STEMP2 + MODEM2=$(cat $STEMP2) + sed -i -e "s!#OPEN#!$MODEM2!g" $STEMP + else + sed -i -e "s!#OPEN#!!g" $STEMP + fi + + band=$(uci -q get iframe.iframe.band) + if [ $band = "1" ]; then + STEMP2="/tmp/www/stemp2.html" + STATUS2="/usr/lib/iframe/band.html" + rm -f $STEMP2 + cp $STATUS2 $STEMP2 + MODEM2=$(cat $STEMP2) + sed -i -e "s!#BWMON#!$MODEM2!g" $STEMP + else + sed -i -e "s!#BWMON#!!g" $STEMP + fi + + mv $STEMP $SPSTATUS +fi + diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/update.sh b/rooter/0splash/ext-splash/files/usr/lib/iframe/update.sh new file mode 100644 index 0000000..bf67d98 --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/update.sh @@ -0,0 +1,95 @@ +#!/bin/sh +. /lib/functions.sh + +bwdata() { + while IFS= read -r line; do + if [ $line = '0' ]; then + nodata="1" + break + else + nodata="0" + days=$line + read -r line + read -r line + tused=$line + read -r line + read -r line + tdwn=$line + read -r line + read -r line + tup=$line + read -r line + read -r line + project=$line + break + fi + done < /tmp/bwdata +} + +logtype=$(uci -q get iframe.login.logtype) +if [ $logtype = "1" ]; then + STEMP="/tmp/www/itemp.html" + STATUS="/usr/lib/iframe/iframe.html" + IFSTATUS="/tmp/www/display.html" + + rm -f $STEMP + cp $STATUS $STEMP + bwdata + + sed -i -e "s!#TITLE#!Bandwidth Usage!g" $STEMP + sed -i -e "s!#DAYS#!$days!g" $STEMP + sed -i -e "s!#TOTAL#!$tused!g" $STEMP + sed -i -e "s!#DOWN#!$tdwn!g" $STEMP + sed -i -e "s!#UP#!$tup!g" $STEMP + sed -i -e "s!#PROJ#!$project!g" $STEMP + + mv $STEMP $IFSTATUS +fi + +if [ $logtype = "2" ]; then + STEMP="/tmp/www/itemp.html" + STATUS="/usr/lib/iframe/image.html" + IFSTATUS="/tmp/www/display.html" + + rm -f $STEMP + cp $STATUS $STEMP + logimage=$(uci -q get iframe.login.logimage) + sed -i -e "s!#IMAGE#!$logimage!g" $STEMP + logimagewidth=$(uci -q get iframe.login.logimagewidth) + sed -i -e "s!#WIDTH#!$logimagewidth!g" $STEMP + + mv $STEMP $IFSTATUS +fi + +if [ $logtype = "4" ]; then + STEMP="/tmp/www/itemp.html" + STATUS="/usr/lib/iframe/speed.html" + IFSTATUS="/tmp/www/display.html" + + rm -f $STEMP + cp $STATUS $STEMP + + mv $STEMP $IFSTATUS +fi + +if [ $logtype = "3" ]; then + STEMP="/tmp/www/itemp.html" + STATUS="/usr/lib/iframe/zerotier.html" + IFSTATUS="/tmp/www/display.html" + + rm -f $STEMP + cp $STATUS $STEMP + + ID=$(uci -q get zerotier.zerotier.secret) + if [ -z $ID ]; then + ID="xxxxxxxxxx" + else + ID=${ID:0:10} + fi + + sed -i -e "s!#ID#!$ID!g" $STEMP + source /etc/codename + sed -i -e "s!#VER#!$CODENAME!g" $STEMP + + mv $STEMP $IFSTATUS +fi \ No newline at end of file diff --git a/rooter/0splash/ext-splash/files/usr/lib/iframe/zerotier.html b/rooter/0splash/ext-splash/files/usr/lib/iframe/zerotier.html new file mode 100644 index 0000000..aaba6a5 --- /dev/null +++ b/rooter/0splash/ext-splash/files/usr/lib/iframe/zerotier.html @@ -0,0 +1,14 @@ + + + + + + + + + +

                          Router ID : #ID#

                          +
                          Powered by : #VER#
                          + + + diff --git a/rooter/0splash/ext-splash/files/www/luci-static/display.html b/rooter/0splash/ext-splash/files/www/luci-static/display.html new file mode 100644 index 0000000..acc2f86 --- /dev/null +++ b/rooter/0splash/ext-splash/files/www/luci-static/display.html @@ -0,0 +1 @@ +/tmp/www/display.html \ No newline at end of file diff --git a/rooter/0splash/ext-splash/files/www/luci-static/iframe.html b/rooter/0splash/ext-splash/files/www/luci-static/iframe.html new file mode 100644 index 0000000..444edca --- /dev/null +++ b/rooter/0splash/ext-splash/files/www/luci-static/iframe.html @@ -0,0 +1 @@ +/tmp/www/daylist.html \ No newline at end of file diff --git a/rooter/0splash/ext-splash/files/www/luci-static/ifstatus.html b/rooter/0splash/ext-splash/files/www/luci-static/ifstatus.html new file mode 100644 index 0000000..1155573 --- /dev/null +++ b/rooter/0splash/ext-splash/files/www/luci-static/ifstatus.html @@ -0,0 +1 @@ +/tmp/www/ifstatus.html \ No newline at end of file diff --git a/rooter/0splash/ext-splash/files/www/luci-static/rooter/css/iconmoon_splash.css b/rooter/0splash/ext-splash/files/www/luci-static/rooter/css/iconmoon_splash.css new file mode 100644 index 0000000..5254b92 --- /dev/null +++ b/rooter/0splash/ext-splash/files/www/luci-static/rooter/css/iconmoon_splash.css @@ -0,0 +1,69 @@ +@font-face { + font-family: 'icomoon_splash'; + src: url('../fonts/icomoon_splash.eot?vja16g'); + src: url('../fonts/icomoon_splash.eot?vja16g#iefix') format('embedded-opentype'), + url('../fonts/icomoon_splash.ttf?vja16g') format('truetype'), + url('../fonts/icomoon_splash.woff?vja16g') format('woff'), + url('../fonts/icomoon_splash.svg?vja16g#icomoon_splash') format('svg'); + font-weight: normal; + font-style: normal; +} + +[class^="icon-"], [class*=" icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'icomoon_splash' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + + +.icon-power-off:before { + content: "\f011"; +} +.icon-signal:before { + content: "\f012"; +} +.icon-cog:before { + content: "\f013"; +} +.icon-gear:before { + content: "\f013"; +} +.icon-home:before { + content: "\f015"; +} +.icon-exclamation-triangle:before { + content: "\f071"; +} +.icon-warning:before { + content: "\f071"; +} +.icon-comments:before { + content: "\f086"; +} +.icon-hdd-o:before { + content: "\f0a0"; +} +.icon-plug:before { + content: "\f1e6"; +} +.icon-wifi:before { + content: "\f1eb"; +} +.icon-connection:before { + content: "\e91b"; +} +.icon-podcast:before { + content: "\e91c"; +} +.icon-earth:before { + content: "\e9ca"; +} diff --git a/rooter/0splash/ext-splash/files/www/luci-static/rooter/css/splash.css b/rooter/0splash/ext-splash/files/www/luci-static/rooter/css/splash.css new file mode 100644 index 0000000..05040a4 --- /dev/null +++ b/rooter/0splash/ext-splash/files/www/luci-static/rooter/css/splash.css @@ -0,0 +1,342 @@ +/* @override http://src.dev.lo.lo/ROOter/www/luci-static/rooter/css/splash.css */ + +/* + CSS for ROOter splash pages + Copyright Francois Dechery + https://github.com/soif +*/ + +/* @group Splash Pages +--------------------------------------------------*/ + +.rooterSplash{ + padding: 0; + background: #F0F0F0; +} +.rooterPageHead{ + background: #55F; + padding: 20px 5px; + background: rgb(140,140,255); + background: -moz-linear-gradient(top, rgba(140,140,255,1) 0%, rgba(85,85,255,1) 100%); + background: -webkit-linear-gradient(top, rgba(140,140,255,1) 0%,rgba(85,85,255,1) 100%); + background: linear-gradient(to bottom, rgba(140,140,255,1) 0%,rgba(85,85,255,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#8c8cff', endColorstr='#5555ff',GradientType=0 ); + border-bottom: 1px solid rgba(0,0,0,0.7); + +} +.rooterPageContent{ + border-top: 1px solid rgba(255,255,255,0.8); + border-bottom: 1px solid rgba(0,0,0, 0.1); + padding: 0px 0px; + max-width: 1200px; + margin: auto; +} + +.rooterPageContentBW{ + border-top: 1px solid rgba(255,255,255,0.8); + border-bottom: 1px solid rgba(0,0,0, 0.1); + padding: 10px 0px; + max-width: 600px; + margin: auto; +} + +.rooterHeadTitle{ + color: #fff; + text-align: center; + font-family: Georgia, "Times New Roman", Times, serif; + font-size: 32px; + line-height: 120%; + text-shadow: -1px -1px 2px rgba(0,0,0,0.5); +} +.rooterPageFoot{ + border-top: 1px solid rgba(255,255,255,0.8); + margin-top: 20px; + padding: 10px 10px; + max-width: 950px; + margin: auto; + font-size: 16px; +} +.rooterFootMenu{ + float: left; + margin-bottom: 10px; +} +.rooterFootMenu A{ + text-decoration: none; +} +.rooterFootMenu A:hover{ + color: #000; +} +.rooterFootMenu UL{ + padding: 0; + margin: 0; + overflow: hidden; + display: inline-block; +} +.rooterFootMenu LI{ + float: left; + padding: 0; + margin: 0; + list-style: none; +} +.rooterFootMenu LI A{ + padding: 0 10px; + color: #555; +} +.rooterFootMenu LI:first-child A{ + padding-left: 0; +} +.rooterFootCredits{ + float: right; + padding: 0; + margin: 0; + color: #999; + text-align: right; +} +.rooterFootCredits A{ + color: #777; +} +/* @end */ + + + + +/* @group Page: Home +--------------------------------------------------*/ + + +/* @group Logo +++++++++++++++++++ */ +.rooterHeadBox{ + font-size: 50px; + font-family: Georgia, "Times New Roman", Times, serif; + color: #fff; + line-height: 100%; + overflow: hidden; + width: 700px; + margin: auto; + padding-top: 10px; + opacity: 0; +} +.rooterLogo{ + background: url("../img/kangaroo_800.png") no-repeat; + background-size: 100%; + float: left; + height: 110px; + width: 250px; + opacity: 0.4; +} +.rooterTagline{ + margin-left: 100px; + padding-left: 10px; + text-shadow: 2px 2px 3px rgba(0,0,0,0.3); +} + +/* @end */ + +@media only screen and (max-width: 600px) { + .rooterHeadBox{ + text-align: center; + width: auto; + } + .rooterLogo{ + display: inline-block; + float: none; + } + .rooterTagline { + display: none; + } + .rooterFootCredits, + .rooterFootMenu{ + float: none; + text-align: center; + } +} + +#rooterItems{ + clear: both; + max-width: 600px ; + margin: auto; +} + +#rooterItemss{ + clear: both; + max-width: 300px ; + margin: auto; +} +.rooterItem{ + overflow: hidden; + border: 5px solid #00; + border-color: #00 #DDD #DDD #00; + padding: 20px 15px; + margin-bottom: 20px; + border-radius: 8px; + background-color: #AFAFAF; +} +.rooterItem:hover{ + background-color: #CFCFCF; + border-color: #AAA; +} +.rooterItemTitle{ + float: left; + font-size: 18px; + font-weight: bold; + padding-right: 10px; + color: #000; + line-height: 2em; +} +.rooterItemTitle .icon{ + color: #55F; + margin-right: 8px; + font-size: 2em; + vertical-align: middle; +} + +.rooterItemsp{ + overflow: hidden; + border: 5px solid #00; + border-color: #00 #DDD #DDD #00; + padding: 5px 15px; + margin-bottom: 5px; + border-radius: 8px; + background-color: #AFAFAF; + max-width: 300px ; +} +.rooterItemsp:hover{ + background-color: #CFCFCF; + border-color: #AAA; +} + +#rooterItems A{ + text-decoration: none; +} +.rooterItemDesc{ + font-size: 18px; + color: #777; + margin-left: 220px; + margin-top: 0.7em; +} +/* @end */ + + + +/* @group Page: Status +--------------------------------------------------*/ + +.modemStatusBlock{ + margin-bottom: 30px; +} +#rooterSplashStatus h3{ + clear:both; + font-size: 18px; + color: #55F; +} +#rooterSplashStatus h3 .icon{ + margin-right: 3px; +} +#rooterSplashStatus h3 .msCell{ + color: #666; +} +.modemStatusRow{ + clear:both; + padding-bottom: 20px; + overflow: hidden; +} +.modemStatusRow .msTitle{ + border-radius: 2px 2px 0 0; + padding: 5px 5px ; + background: #484848; + color: #fff; + background: rgb(99,99,99); + background: -moz-linear-gradient(top, rgba(99,99,99,1) 0%, rgba(72,72,72,1) 100%); + background: -webkit-linear-gradient(top, rgba(99,99,99,1) 0%,rgba(72,72,72,1) 100%); + background: linear-gradient(to bottom, rgba(99,99,99,1) 0%,rgba(72,72,72,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#636363', endColorstr='#484848',GradientType=0 ); +} +.modemStatusRow .msCell{ + border-radius: 10px; + display: inline-block; + margin-top: 10px; + float:left; + border: 1px solid #ccc; + padding-bottom: 5px; + background: #fff; + +} +.modemStatusRow1 .msCell{ + width: 176px; + margin: 10px 5px 0 5px; + text-align: center; +} +.modemStatusRow1 SPAN B{ + font-weight: bold; + font-size: 35px; + line-height: 110%; + text-shadow: 1px 1px 1px rgba(0,0,0,0.4); +} +.modemStatusRow1 .msDesc{ + color: #000; + font-size: 12px; +} +.modemStatusRow2 .msCell{ + margin: 10px 5px; + text-align: center; +} +.modemStatusRow2 SPAN{ + display: inline-block; + padding: 5px 5px ; + font-size: 14px; +} +#counter_div{ + color: #000; + font-weight: normal; + font-size: 14px; +} +#counter_val{ + color: #F00; + font-size: 32px; + font-weight: bold; + text-shadow: 1px 1px 1px rgba(0,0,0,0.1); +} +#msCell_per{} +#msCell_csq{} +#msCell_rssi{} +#msCell_rscp{} +#msCell_ecio{} + +#rooterSplashStatus .level_0{ + color: #0F0; // green +} +#rooterSplashStatus .level_1{ + color: #0CB; // green blue +} +#rooterSplashStatus .level_2{ + color: #00F; // blue +} +#rooterSplashStatus .level_3{ + color: #F0F; // violet +} +#rooterSplashStatus .level_4{ + color: #F80; // orange +} +#rooterSplashStatus .level_5{ + color: #F00; // red +} +#rooterSplashStatus .level_6{ + color: #FF0; // yellow +} + +/* @end */ + + +/* Easy Color changer ------------- */ + +.rooterPageHead{ + /*background: #55F;*/ +} +.rooterItemTitle .icon, +#rooterSplashStatus h3{ + color: #55F; +} + + + diff --git a/rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.eot b/rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.eot new file mode 100644 index 0000000000000000000000000000000000000000..29cd4d1f36a419b4822d210be985dbde03d1d3ac GIT binary patch literal 4708 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 Gn*ReFo8=Jz literal 0 HcmV?d00001 diff --git a/rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.svg b/rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.svg new file mode 100644 index 0000000..dc2127b --- /dev/null +++ b/rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.svg @@ -0,0 +1,22 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.ttf b/rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4e27645c4f897ba62acace85a644aff591860682 GIT binary patch literal 4516 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 E0b}jXx&QzG literal 0 HcmV?d00001 diff --git a/rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.woff b/rooter/0splash/ext-splash/files/www/luci-static/rooter/fonts/icomoon_splash.woff new file mode 100644 index 0000000000000000000000000000000000000000..63f541307f5f723c6eed5ef792b2fbce8e4ea0f7 GIT binary patch literal 4592 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 Vg5RoPjlsG#(%?z@pM}q8{|Cw&)JOmT literal 0 HcmV?d00001 diff --git a/rooter/0splash/ext-splash/files/www/luci-static/rooter/img/favicon.gif b/rooter/0splash/ext-splash/files/www/luci-static/rooter/img/favicon.gif new file mode 100644 index 0000000000000000000000000000000000000000..bfbe292825c753540fdd42af7823e167398874e3 GIT binary patch literal 2441 zcmeH|`8yMi1ILGvYixGm<15Ef&K%XGWGY8nBu7{bHJZ6{Bq|yscV0Es=-6N-A(-ME%9Np_=t!2*uVA^pYRf&^oF*( z!kS&-EpG5uH*l{TxRV6!^#p$+f%{32esA!AJ7mBc^4SMD;Dwm+ z27mR1ehY+82SVo_AZCK0^C8fMhtQw*U`zLPrpg^~%uvH4| zR~USY0^6d(w<)k~Dq=SrwjF`kjeze(!gizJ`%%b)NW{S-BsU7a7me79g>z!yoLB@m z8qSS@AH>4BaR_d_>~^fmdYtMGUF{$RKa+-^Prtszyu;22{FEKml}G8$3+pfZFU$YO z{}=)J9UuHTLD06{K*D3&R(~8_?#haa^F?N!o zlsMu-tc*~Fu@K71ve@CNwg^8j>SkxAJ@sOYs-55BSd6OxPnr%@m}yrPk)mpvtnxqj0ew6D_ujjAtxs9Bikc{4)t`0#pbMT~G)cdhPSVxAf6tlIkb>#o#LkpANO z;*El?g2y5AzgOIAzHw*8vYrPu&2+urXN7WtTbHZ$vY6*WO*c1xHrYBD7#QszaOw^d z>-k?yKIn&&oQ(h)c6}6<@_hD1kok~BBm&DXe_Lv#M&9c`gl(6H@=6gdF#^nJ1w$3q zF^f2j*81G|V|}KX5S#M+Z&*1Q;?3Je^O(1f)qK|s!wi010}AN{OwS}+=n3)Nx%9mj zCD!EF!keOq9hyk7_l_Yxfrjs7q@ANLWIrvxrrz?4nF=Hb1PTZ#U53oQz)4~-1p@N; zl-%RmD#L{+P3~F-*dPZ_E5=pqCNeErR6IPYv&hQNy~w*#g~dC19;I!M+<*AU-NT-L z*(IE@SkUvhVIhdg`&_NOn}GX~+1vMJnJ~$Mzbpk#7c*F|l^AccH-v>Fqy-9apI?1& zD_*V`Gd@DhSLNKsNbi{MmAsmsh%Ie$_l}!rKqS#FzzM{cYwrlhd;vUy$b28${n!kz zcEA-GxR4@dZB&eplBroUgQrx%@n-`Q9Bew!&-S0UuNuCs>?&B_p0{s(0hOWAe)8jP-l7 zm9g(i8~0aBK~87;bLP}PPGEnJ?@yK#v$U6*MXv164IM7y7>pgA4H@d06Xo>GST&{o zp7-HwZzdi0(OV?q?EA#D_17J*JgnbKU&(skIL{sIrR=ng9t?dkpubtZpE7DSEQosZ z%jV|;!6HXnZ}h8Lds^@+pA)McjrsQ&sD~KNytq2d&PiG*aAS&t2?9f|MMiY!On=l! zYZcWXQz47l9CmmUSlTCoP0jpezTLFV;~g5_H7(KD*DiZ*E$ZsbBrGbrwclRrft>>r zAwS=~VdxvOe4%r%`$g;BijSUHVjgl_&{+2xE#Bs3-rx$m^S7uIr(ODA>bOQRd!76+^)JBhkVD(k)@2uP$fz8W(i z=w7z%1g8o!W>-kVjc05963awysKuSabrsQ1jkO=qnyl|42lg_Wtlc!97MYNKT}=x;&gqW3TbnA}QSS95oj9!b!RS?JE&sX zfbY3Z56Hsl7oD^se@eN*D7{-YPSQFF9%R>M7)=@9+TG+iloJO0ao-8aJR%1;^ACjV#SQ=f literal 0 HcmV?d00001 diff --git a/rooter/0splash/ext-splash/files/www/luci-static/rooter/img/kangaroo_800.png b/rooter/0splash/ext-splash/files/www/luci-static/rooter/img/kangaroo_800.png new file mode 100644 index 0000000000000000000000000000000000000000..478fa6d62f4ce758358142fefd480c564773ce36 GIT binary patch literal 5836 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 Wk|dU(LN#0f0000DzfNY>Fh|Ltj$Y2csQN9XW literal 0 HcmV?d00001 diff --git a/rooter/0splash/ext-splashconfig/Makefile b/rooter/0splash/ext-splashconfig/Makefile new file mode 100644 index 0000000..c986ca8 --- /dev/null +++ b/rooter/0splash/ext-splashconfig/Makefile @@ -0,0 +1,36 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-splashconfig +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/ext-splashconfig + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Splash Screens + DEPENDS:=+ext-splash + TITLE:=Added scripts for Login display + PKGARCH:=all +endef + +define Package/ext-splashconfig/description + Added scripts for Login display +endef + + +define Build/Compile +endef + +define Package/ext-splashconfig/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-splashconfig)) diff --git a/rooter/0splash/ext-splashconfig/files/usr/lib/lua/luci/controller/splash.lua b/rooter/0splash/ext-splashconfig/files/usr/lib/lua/luci/controller/splash.lua new file mode 100644 index 0000000..84f6b85 --- /dev/null +++ b/rooter/0splash/ext-splashconfig/files/usr/lib/lua/luci/controller/splash.lua @@ -0,0 +1,13 @@ +--[[ +ext-theme +]]-- + +module("luci.controller.splash", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + entry({"admin", "splash"}, firstchild(), translate("Splash Screen"), 99).dependent=false + entry({"admin", "splash", "splash"}, cbi("splashm"), _(translate("Configuration")), 20) +end diff --git a/rooter/0splash/ext-splashconfig/files/usr/lib/lua/luci/model/cbi/splashm.lua b/rooter/0splash/ext-splashconfig/files/usr/lib/lua/luci/model/cbi/splashm.lua new file mode 100644 index 0000000..4703b22 --- /dev/null +++ b/rooter/0splash/ext-splashconfig/files/usr/lib/lua/luci/model/cbi/splashm.lua @@ -0,0 +1,44 @@ + + +local sys = require "luci.sys" +local zones = require "luci.sys.zoneinfo" +local fs = require "nixio.fs" +local conf = require "luci.config" + +m = Map("iframe", translate("Splash Screen Configuration"),translate("Change the configuration of the Splash and Login screen.")) +m:chain("luci") + +s = m:section(TypedSection, "iframe", translate("Status Page Configuration")) +s.anonymous = true +s.addremove = false + +c1 = s:option(ListValue, "splashpage", translate("Enable Network Status Page Before Login :")); +c1:value("0", translate("Disabled")) +c1:value("1", translate("Enabled")) +c1.default=0 + +a1 = s:option(Value, "splashtitle", translate("Network Status Title :")); +a1.optional=false; +a1.default = translate("ROOter Status") +a1:depends("splashpage", "1") + +dc1 = s:option(ListValue, "dual", translate("Enable Modem 2 Status :")); +dc1:value("0", translate("Disabled")) +dc1:value("1", translate("Enabled")) +dc1.default=0 +dc1:depends("splashpage", "1") + +cc1 = s:option(ListValue, "speed", translate("Enable OpenSpeedTest :")); +cc1:value("0", translate("Disabled")) +cc1:value("1", translate("Enabled")) +cc1.default=0 +cc1:depends("splashpage", "1") + +ec1 = s:option(ListValue, "band", translate("Enable Bandwidth Summary :")); +ec1:value("0", translate("Disabled")) +ec1:value("1", translate("Enabled")) +ec1.default=0 +ec1:depends("splashpage", "1") + + +return m \ No newline at end of file diff --git a/rooter/0splash/splash/Makefile b/rooter/0splash/splash/Makefile new file mode 100644 index 0000000..2941b94 --- /dev/null +++ b/rooter/0splash/splash/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=splash +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/splash + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Splash Screens + TITLE:=Added scripts for Splash screen + PKGARCH:=all +endef + +define Package/splash/description + Added scripts for Splash screen +endef + + +define Build/Compile +endef + +define Package/splash/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,splash)) diff --git a/rooter/0splash/splash/files/www/luci-static/rooter/css/iconmoon_splash.css b/rooter/0splash/splash/files/www/luci-static/rooter/css/iconmoon_splash.css new file mode 100644 index 0000000..5254b92 --- /dev/null +++ b/rooter/0splash/splash/files/www/luci-static/rooter/css/iconmoon_splash.css @@ -0,0 +1,69 @@ +@font-face { + font-family: 'icomoon_splash'; + src: url('../fonts/icomoon_splash.eot?vja16g'); + src: url('../fonts/icomoon_splash.eot?vja16g#iefix') format('embedded-opentype'), + url('../fonts/icomoon_splash.ttf?vja16g') format('truetype'), + url('../fonts/icomoon_splash.woff?vja16g') format('woff'), + url('../fonts/icomoon_splash.svg?vja16g#icomoon_splash') format('svg'); + font-weight: normal; + font-style: normal; +} + +[class^="icon-"], [class*=" icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'icomoon_splash' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + + +.icon-power-off:before { + content: "\f011"; +} +.icon-signal:before { + content: "\f012"; +} +.icon-cog:before { + content: "\f013"; +} +.icon-gear:before { + content: "\f013"; +} +.icon-home:before { + content: "\f015"; +} +.icon-exclamation-triangle:before { + content: "\f071"; +} +.icon-warning:before { + content: "\f071"; +} +.icon-comments:before { + content: "\f086"; +} +.icon-hdd-o:before { + content: "\f0a0"; +} +.icon-plug:before { + content: "\f1e6"; +} +.icon-wifi:before { + content: "\f1eb"; +} +.icon-connection:before { + content: "\e91b"; +} +.icon-podcast:before { + content: "\e91c"; +} +.icon-earth:before { + content: "\e9ca"; +} diff --git a/rooter/0splash/splash/files/www/luci-static/rooter/css/splash.css b/rooter/0splash/splash/files/www/luci-static/rooter/css/splash.css new file mode 100644 index 0000000..76957ea --- /dev/null +++ b/rooter/0splash/splash/files/www/luci-static/rooter/css/splash.css @@ -0,0 +1,311 @@ +/* @override http://src.dev.lo.lo/ROOter/www/luci-static/rooter/css/splash.css */ + +/* + CSS for ROOter splash pages + Copyright Francois Dechery + https://github.com/soif +*/ + +/* @group Splash Pages +--------------------------------------------------*/ + +.rooterSplash{ + padding: 0; + background: #F0F0F0; +} +.rooterPageHead{ + background: #55F; + padding: 10px 5px; + background: rgb(140,140,255); + background: -moz-linear-gradient(top, rgba(140,140,255,1) 0%, rgba(85,85,255,1) 100%); + background: -webkit-linear-gradient(top, rgba(140,140,255,1) 0%,rgba(85,85,255,1) 100%); + background: linear-gradient(to bottom, rgba(140,140,255,1) 0%,rgba(85,85,255,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#8c8cff', endColorstr='#5555ff',GradientType=0 ); + border-bottom: 1px solid rgba(0,0,0,0.7); + +} +.rooterPageContent{ + border-top: 1px solid rgba(255,255,255,0.8); + border-bottom: 1px solid rgba(0,0,0, 0.1); + padding: 25px 10px; + max-width: 950px; + margin: auto; +} +.rooterHeadTitle{ + color: #fff; + text-align: center; + font-family: Georgia, "Times New Roman", Times, serif; + font-size: 32px; + line-height: 120%; + text-shadow: -1px -1px 2px rgba(0,0,0,0.5); +} +.rooterPageFoot{ + border-top: 1px solid rgba(255,255,255,0.8); + margin-top: 20px; + padding: 10px 10px; + max-width: 950px; + margin: auto; + font-size: 11px; +} +.rooterFootMenu{ + float: left; + margin-bottom: 10px; +} +.rooterFootMenu A{ + text-decoration: none; +} +.rooterFootMenu A:hover{ + color: #000; +} +.rooterFootMenu UL{ + padding: 0; + margin: 0; + overflow: hidden; + display: inline-block; +} +.rooterFootMenu LI{ + float: left; + padding: 0; + margin: 0; + list-style: none; +} +.rooterFootMenu LI A{ + padding: 0 10px; + color: #555; +} +.rooterFootMenu LI:first-child A{ + padding-left: 0; +} +.rooterFootCredits{ + float: right; + padding: 0; + margin: 0; + color: #999; + text-align: right; +} +.rooterFootCredits A{ + color: #777; +} +/* @end */ + + + + +/* @group Page: Home +--------------------------------------------------*/ + + +/* @group Logo +++++++++++++++++++ */ +.rooterHeadBox{ + font-size: 50px; + font-family: Georgia, "Times New Roman", Times, serif; + color: #fff; + line-height: 100%; + overflow: hidden; + width: 700px; + margin: auto; + padding-top: 10px; + opacity: 0; +} +.rooterLogo{ + background: url("../img/kangaroo_800.png") no-repeat; + background-size: 100%; + float: left; + height: 110px; + width: 250px; + opacity: 0.4; +} +.rooterTagline{ + margin-left: 100px; + padding-left: 10px; + text-shadow: 2px 2px 3px rgba(0,0,0,0.3); +} + +/* @end */ + +@media only screen and (max-width: 600px) { + .rooterHeadBox{ + text-align: center; + width: auto; + } + .rooterLogo{ + display: inline-block; + float: none; + } + .rooterTagline { + display: none; + } + .rooterFootCredits, + .rooterFootMenu{ + float: none; + text-align: center; + } +} + +#rooterItems{ + clear: both; + max-width: 800px ; + margin: auto; +} +.rooterItem{ + overflow: hidden; + border: 1px solid #EEE; + border-color: #EEE #DDD #DDD #EEE; + padding: 20px 15px; + margin-bottom: 20px; + border-radius: 8px; + background-color: #fff; +} +.rooterItem:hover{ + background-color: #F3F3FF; + border-color: #AAA; +} +.rooterItemTitle{ + float: left; + font-size: 18px; + font-weight: bold; + padding-right: 10px; + color: #000; + line-height: 2em; +} +.rooterItemTitle .icon{ + color: #55F; + margin-right: 8px; + font-size: 2em; + vertical-align: middle; +} +#rooterItems A{ + text-decoration: none; +} +.rooterItemDesc{ + font-size: 14px; + color: #777; + margin-left: 220px; + margin-top: 0.7em; +} +/* @end */ + + + +/* @group Page: Status +--------------------------------------------------*/ + +.modemStatusBlock{ + margin-bottom: 30px; +} +#rooterSplashStatus h3{ + clear:both; + font-size: 18px; + color: #55F; +} +#rooterSplashStatus h3 .icon{ + margin-right: 3px; +} +#rooterSplashStatus h3 .msCell{ + color: #666; +} +.modemStatusRow{ + clear:both; + padding-bottom: 20px; + overflow: hidden; +} +.modemStatusRow .msTitle{ + border-radius: 2px 2px 0 0; + padding: 5px 5px ; + background: #484848; + color: #fff; + background: rgb(99,99,99); + background: -moz-linear-gradient(top, rgba(99,99,99,1) 0%, rgba(72,72,72,1) 100%); + background: -webkit-linear-gradient(top, rgba(99,99,99,1) 0%,rgba(72,72,72,1) 100%); + background: linear-gradient(to bottom, rgba(99,99,99,1) 0%,rgba(72,72,72,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#636363', endColorstr='#484848',GradientType=0 ); +} +.modemStatusRow .msCell{ + border-radius: 10px; + display: inline-block; + margin-top: 10px; + float:left; + border: 1px solid #ccc; + padding-bottom: 5px; + background: #fff; + +} +.modemStatusRow1 .msCell{ + width: 176px; + margin: 10px 5px 0 5px; + text-align: center; +} +.modemStatusRow1 SPAN B{ + font-weight: bold; + font-size: 70px; + line-height: 110%; + text-shadow: 1px 1px 1px rgba(0,0,0,0.4); +} +.modemStatusRow1 .msDesc{ + color: #000; + font-size: 12px; +} +.modemStatusRow2 .msCell{ + margin: 10px 5px; + text-align: center; +} +.modemStatusRow2 SPAN{ + display: inline-block; + padding: 5px 5px ; + font-size: 14px; +} +#counter_div{ + color: #000; + font-weight: normal; + font-size: 14px; +} +#counter_val{ + color: #F00; + font-size: 32px; + font-weight: bold; + text-shadow: 1px 1px 1px rgba(0,0,0,0.1); +} +#msCell_per{} +#msCell_csq{} +#msCell_rssi{} +#msCell_rscp{} +#msCell_ecio{} + +#rooterSplashStatus .level_0{ + color: #0F0; // green +} +#rooterSplashStatus .level_1{ + color: #0CB; // green blue +} +#rooterSplashStatus .level_2{ + color: #00F; // blue +} +#rooterSplashStatus .level_3{ + color: #F0F; // violet +} +#rooterSplashStatus .level_4{ + color: #F80; // orange +} +#rooterSplashStatus .level_5{ + color: #F00; // red +} +#rooterSplashStatus .level_6{ + color: #FF0; // yellow +} + +/* @end */ + + +/* Easy Color changer ------------- */ + +.rooterPageHead{ + /*background: #55F;*/ +} +.rooterItemTitle .icon, +#rooterSplashStatus h3{ + color: #55F; +} + + + diff --git a/rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.eot b/rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.eot new file mode 100644 index 0000000000000000000000000000000000000000..29cd4d1f36a419b4822d210be985dbde03d1d3ac GIT binary patch literal 4708 zcma(VYiwIr`J8+1!@j=uwS9eUCr)g~?>dPcKd#-Tb{^fD*2zNBrb*UhS(~*XY1brO zlWOhC+DJed>rh7qljsJFX+ub8gCA4F&?G8^1mdBwUm#lT542EKLM_q&L7VWMd!5$F zrm>@Y?>XP=JigaC=N@(<^o9c=j2N`BVDuuUm`4UT;wi6D%m*KRcQXy426O}+Li1=A z-gz{K4xj~e934ZGP|pCn4edo!Xd0c=aVG%dMk9bZ0rVrfL=a_A3f}+U7qHODSkMw8 zsBK^84FG>*dUD}7)OLV>47F+c*y+#z@IupX0R9O= zR{PA<LmMx0T!K?Wb;^zx~>s8+UH4-CJ9uodC@TG{?ticeQPx&MHl6+pC zwIys3=&yDjdIvQhj4<>n*YJSj6}Rak59B@_$08mf_CI6^oT&xv2j@XJ>-GpK91ih9 zyaVT=g<=OT7IImSAA5iji>Gir77htEEbsz$8|cg?eB6*KZV<+K=*F$O_;4u3EDgMn z9}7=t+C+FP|H8oP_EbK<(9zM=)zPt#&!@&C$>d|1Y%Z70JeEvGm|rGhv0Y7}z<8mv z^ZDN1{{G(H=Q}$KSeS!x%#!J&ljaHUMgv0;Y1=lrj>TKhQn#A zBw5qpaO-%ap&=$hi8VAt@b4X}E8}bMj~9~3cAG5Q+LOt`xWB=daj6c6)#~I}mUCLI zcRw<^je^b5+7%XoxA;*j8blXBZ~0oysIIEMnyRYcQdnDGzYrHZ9RPwFdDW$>Tg%s~ z8FVDXm8zun$sHSp*eqw5g++;t-JSEhns50 z?Wn8EwY2wXT3>rh-@~IWS5GRfY3Wpt%QgCN-^-PBBGGQQ*VT=-Z{M+Fd;4fzo!#D^ zNTe&JY<9QH6^@+VyJuoz&)(CKu*Qa$Fk8_x}BnYLaxl-{NVa(3U)#LlkHC$}W)X?TFgS8d~iM2N8As#SyJvbvtDIwhf4 zT6>Bn?+~HC=iC?lRqG_%r9L`y7ZuKNDaZ4=c?{3l#wGf{88XJ8L zJu!x3c%EZ<&WZie$exx~a;4V5we7oIiUSL*g+FLjoJx!0#4M*+ubAy@@x4GIen8W< z=KOKZx%gn!Vw>Y&@P{^Q3;0*l(zR^f`i_=un370bP1_%j;x>(g6xc4`tsIw zW%z8d;P$xbx;LwsY7evxS%any6+86E*Bp8nkhyT^)ZpOQ_~78vp|E6WZED(5S8_Vd z-eQNxGpK3hQb8N=c*{vV=P|RL$ z$(cN}v#e=@9w@Y*ooA9D?=>rdczi6I$>WvPW!eXxgD)(Pqicj%o`YOUH_RPq2=XX| zAUHw{T%)iZQsQPYf_&7q@%&`oH7AzKF&Lm#5m}X5D{c{ztCQ<*?Vs$oM zU};@Q>|UYbE0lYARd3@8?d96NtCYY*DFsLF>Lj9*U}@_%oP*tcndYf#+5wl2!YXA9 z&I|_fgZ-!#AvvchN`L4I(-<YDNHF;K{PS|yibA%2~d>&P~`+L3;-Yv zotmLwSV~cu%1Eg^JX|h~;HX(R%87z4U}soD#9^5g*a4~DMtFg-n9d0jwp;71gTzEw z6LA-u48ssxKsHJ2jLB@~pJXk9?6(s_7|XB>Tm!&O1dtWZnRHoc4-r^aARa197?2et zZblICN@+x&#hG)w729p~k{Va&FaojeCrk%#;pz+Zf>{)fa3Wu3U>PuH; zH^#eh1)mE;K4Dm%SzTN`sn44Ua}0-Haps&CbWePif=jD^m)+N{xn=Cc43<~#FgTuM zScbv9tCtyqStiNL93GM7#d+#`H)lARhm#5<3-T|>6Ecd?nMYxFgE{Jn6sA;&D|wm@ zC<WUStqkp}RAz(0t3x~Gu!A!(SQ4yWsd+Hs&DMYJ`GQn0 zrCM8tV)3S3{Q|#xltD(0& z%m{qFQ}O1%+V5^r6VL1dUC=yOfm|O&5~@QN!eeB}t;_qA@ypZ?^$+;00%^ds`t{4PLLqip zQbj!OkH!3}Z;Gk}>w|Og+6uWvUPo~N+%6e=VBZGw#o|I(D}oaiijdAc#X{DjQ)z?T zQq}9j-C4_{YRH_*;Q4Rc_T7wuu6f&IpUBIprx2BPJ@id}p$MDw$u^!q83DijFdWz~~+ zmA>J8ZKQCW&p5cOpVD=&1RHKVj#t^4ie=w`-9E7IB0t>OIn0ZrgruJ9?D|TIkP*wP zkluREPjnZz4teVsafD@JZRwd}p-?CmXVU2y@QAMvfyw4`$4ljh9x9dR^Z5)2i6ev* zy1OqvqL+)^-9-ji_Y6s(FjX45)ZRWKLQJ=2GOZBa;>fE6_6tR6Rg@7C`inRE6Bbdl zB>atW2x4*M6~Z)!LMh2&ky4>hGed?gkUa}ql3QgcTa#M~kWVechK&)fyY%j(2h9iM z(nrVwhjl1_nEr+JLA|yDx1K8in~WR)E$|Kf4rm+*;8s*~v!a4<-!*zN0J^P0$nX?L zU$E!>8uFk5IP-lxBzJZh>`se_TySgnDSnPgF|QFjxxwyWzr#him$^Uk^tMayZg%ui zbsGBaO~q=84ZU5R8-{zEAwhGQfWBMB6TtUX+bp!-skS-rxn#A?1O8;SEyDfvLwet2 z&46hDiqU4E_5Es_0Dgb9%|iR<)iwt=b*0LHn>?}cN6Kdx@0p)l3{FqYO`VuroH`tQ z;&iZbXucoTn?gPM512(bQBK3HdQSf>Gl>?VJ`A`g&}sNq^xr%E)!#cQu%!M^qsG#k Gn*ReFo8=Jz literal 0 HcmV?d00001 diff --git a/rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.svg b/rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.svg new file mode 100644 index 0000000..dc2127b --- /dev/null +++ b/rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.svg @@ -0,0 +1,22 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.ttf b/rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4e27645c4f897ba62acace85a644aff591860682 GIT binary patch literal 4516 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 E0b}jXx&QzG literal 0 HcmV?d00001 diff --git a/rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.woff b/rooter/0splash/splash/files/www/luci-static/rooter/fonts/icomoon_splash.woff new file mode 100644 index 0000000000000000000000000000000000000000..63f541307f5f723c6eed5ef792b2fbce8e4ea0f7 GIT binary patch literal 4592 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 Vg5RoPjlsG#(%?z@pM}q8{|Cw&)JOmT literal 0 HcmV?d00001 diff --git a/rooter/0splash/splash/files/www/luci-static/rooter/img/favicon.gif b/rooter/0splash/splash/files/www/luci-static/rooter/img/favicon.gif new file mode 100644 index 0000000000000000000000000000000000000000..bfbe292825c753540fdd42af7823e167398874e3 GIT binary patch literal 2441 zcmeH|`8yMi1ILGvYixGm<15Ef&K%XGWGY8nBu7{bHJZ6{Bq|yscV0Es=-6N-A(-ME%9Np_=t!2*uVA^pYRf&^oF*( z!kS&-EpG5uH*l{TxRV6!^#p$+f%{32esA!AJ7mBc^4SMD;Dwm+ z27mR1ehY+82SVo_AZCK0^C8fMhtQw*U`zLPrpg^~%uvH4| zR~USY0^6d(w<)k~Dq=SrwjF`kjeze(!gizJ`%%b)NW{S-BsU7a7me79g>z!yoLB@m z8qSS@AH>4BaR_d_>~^fmdYtMGUF{$RKa+-^Prtszyu;22{FEKml}G8$3+pfZFU$YO z{}=)J9UuHTLD06{K*D3&R(~8_?#haa^F?N!o zlsMu-tc*~Fu@K71ve@CNwg^8j>SkxAJ@sOYs-55BSd6OxPnr%@m}yrPk)mpvtnxqj0ew6D_ujjAtxs9Bikc{4)t`0#pbMT~G)cdhPSVxAf6tlIkb>#o#LkpANO z;*El?g2y5AzgOIAzHw*8vYrPu&2+urXN7WtTbHZ$vY6*WO*c1xHrYBD7#QszaOw^d z>-k?yKIn&&oQ(h)c6}6<@_hD1kok~BBm&DXe_Lv#M&9c`gl(6H@=6gdF#^nJ1w$3q zF^f2j*81G|V|}KX5S#M+Z&*1Q;?3Je^O(1f)qK|s!wi010}AN{OwS}+=n3)Nx%9mj zCD!EF!keOq9hyk7_l_Yxfrjs7q@ANLWIrvxrrz?4nF=Hb1PTZ#U53oQz)4~-1p@N; zl-%RmD#L{+P3~F-*dPZ_E5=pqCNeErR6IPYv&hQNy~w*#g~dC19;I!M+<*AU-NT-L z*(IE@SkUvhVIhdg`&_NOn}GX~+1vMJnJ~$Mzbpk#7c*F|l^AccH-v>Fqy-9apI?1& zD_*V`Gd@DhSLNKsNbi{MmAsmsh%Ie$_l}!rKqS#FzzM{cYwrlhd;vUy$b28${n!kz zcEA-GxR4@dZB&eplBroUgQrx%@n-`Q9Bew!&-S0UuNuCs>?&B_p0{s(0hOWAe)8jP-l7 zm9g(i8~0aBK~87;bLP}PPGEnJ?@yK#v$U6*MXv164IM7y7>pgA4H@d06Xo>GST&{o zp7-HwZzdi0(OV?q?EA#D_17J*JgnbKU&(skIL{sIrR=ng9t?dkpubtZpE7DSEQosZ z%jV|;!6HXnZ}h8Lds^@+pA)McjrsQ&sD~KNytq2d&PiG*aAS&t2?9f|MMiY!On=l! zYZcWXQz47l9CmmUSlTCoP0jpezTLFV;~g5_H7(KD*DiZ*E$ZsbBrGbrwclRrft>>r zAwS=~VdxvOe4%r%`$g;BijSUHVjgl_&{+2xE#Bs3-rx$m^S7uIr(ODA>bOQRd!76+^)JBhkVD(k)@2uP$fz8W(i z=w7z%1g8o!W>-kVjc05963awysKuSabrsQ1jkO=qnyl|42lg_Wtlc!97MYNKT}=x;&gqW3TbnA}QSS95oj9!b!RS?JE&sX zfbY3Z56Hsl7oD^se@eN*D7{-YPSQFF9%R>M7)=@9+TG+iloJO0ao-8aJR%1;^ACjV#SQ=f literal 0 HcmV?d00001 diff --git a/rooter/0splash/splash/files/www/luci-static/rooter/img/kangaroo_800.png b/rooter/0splash/splash/files/www/luci-static/rooter/img/kangaroo_800.png new file mode 100644 index 0000000000000000000000000000000000000000..478fa6d62f4ce758358142fefd480c564773ce36 GIT binary patch literal 5836 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 Wk|dU(LN#0f0000 + + + Home - ROOter + + + + + + + + + + + + + + + + + + + +
                          + +
                          + +
                          The ROOter Project
                          +
                          +
                          + + + +
                          +
                          + +
                          +
                          + ROOter Splash Page by Soif and Dairyman +
                          +
                          + + + + diff --git a/rooter/0splash/splash/files/www/splash_files/cellular.png b/rooter/0splash/splash/files/www/splash_files/cellular.png new file mode 100644 index 0000000000000000000000000000000000000000..953bf0897143d03cca60de20b753e2159dbf6927 GIT binary patch literal 8344 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 literal 0 HcmV?d00001 diff --git a/rooter/0splash/splash/files/www/splash_files/check.jpg b/rooter/0splash/splash/files/www/splash_files/check.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f1fb739832977ab446c5bbb382278c8ee4c9c12b GIT binary patch literal 631 zcmex=9X@jO*zpr5PhGlvPb?HxGHT=yahkYr<3UbkKb$@|Xn~>=}ORb!jZ%|9=wzK$gba literal 0 HcmV?d00001 diff --git a/rooter/0splash/splash/files/www/splash_files/forum.png b/rooter/0splash/splash/files/www/splash_files/forum.png new file mode 100644 index 0000000000000000000000000000000000000000..9e8b8c222e46c082eb0bed1621b309f7144d12fe GIT binary patch literal 3845 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 literal 0 HcmV?d00001 diff --git a/rooter/0splash/splash/files/www/splash_files/home.png b/rooter/0splash/splash/files/www/splash_files/home.png new file mode 100644 index 0000000000000000000000000000000000000000..38687c71991b5ed5e17625142388a46dde396ebc GIT binary patch literal 1262 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 literal 0 HcmV?d00001 diff --git a/rooter/0splash/splash/files/www/splash_files/rooter.png b/rooter/0splash/splash/files/www/splash_files/rooter.png new file mode 100644 index 0000000000000000000000000000000000000000..be8099f6b2dd0206a37ee4a6313f3ada97a08528 GIT binary patch literal 311293 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�$6Fa*?Ro&;ozxP$*s2vB9{D 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�!$5oK1*okxLp=Cj1|cI(jc%`*jn;VPZzn^BB|qX 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 literal 0 HcmV?d00001 diff --git a/rooter/0splash/splash/files/www/status.html b/rooter/0splash/splash/files/www/status.html new file mode 100644 index 0000000..930709f --- /dev/null +++ b/rooter/0splash/splash/files/www/status.html @@ -0,0 +1,254 @@ + + + + Live Network Status + + + + + + + + + + + + + + + +

                          +
                          ROOter Live Network Status
                          +
                          + +
                          + + + + + + + +
                          Enter your credentials :
                          + +
                          +

                          0 sec
                          + Signal

                          + +
                          +
                          +
                          Strength (%)
                          + - +
                          +
                          +
                          CSQ
                          + - +
                          +
                          +
                          RSSI (dBm)
                          + - +
                          +
                          +
                          RSCP (dBm) RSRP
                          + - +
                          +
                          +
                          ECIO (dB) RSRQ
                          + - +
                          +
                          +
                          + +
                          +

                          Network -

                          + +
                          +
                          +
                          Mode
                          + - +
                          +
                          +
                          MCC
                          + - +
                          +
                          +
                          MNC
                          + - +
                          +
                          +
                          RNC/eNB ID
                          + - - +
                          + +
                          +
                          LAC
                          + - - +
                          +
                          +
                          Cell ID
                          + - +
                          +
                          +
                          Channel
                          + - +
                          +
                          +
                          Bands
                          + - +
                          +
                          +
                          + +
                          +

                          Device -

                          + +
                          +
                          +
                          Modem
                          + - +
                          +
                          +
                          Protocol
                          + - +
                          +
                          +
                          Port
                          + - +
                          +
                          +
                          Temperature
                          + - +
                          +
                          +
                          + +
                          + +
                          + +
                          +
                          M2M Wireless -- Your Wireless Connection
                          +
                          +
                          + + + diff --git a/rooter/0splash/status/Makefile b/rooter/0splash/status/Makefile new file mode 100644 index 0000000..7bb30c0 --- /dev/null +++ b/rooter/0splash/status/Makefile @@ -0,0 +1,35 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=status +PKG_VERSION:=1.000 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +define Package/status + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Splash Screens + TITLE:=Added scripts for Status Splash screen + PKGARCH:=all +endef + +define Package/status/description + Added scripts for Status Splash screen +endef + + +define Build/Compile +endef + +define Package/status/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,status)) diff --git a/rooter/0splash/status/files/etc/config/splash b/rooter/0splash/status/files/etc/config/splash new file mode 100644 index 0000000..6088b27 --- /dev/null +++ b/rooter/0splash/status/files/etc/config/splash @@ -0,0 +1,4 @@ +config settings 'settings' + option enabled '0' + option full '0' + \ No newline at end of file diff --git a/rooter/0splash/status/files/usr/lib/lua/luci/controller/splashset.lua b/rooter/0splash/status/files/usr/lib/lua/luci/controller/splashset.lua new file mode 100644 index 0000000..37b2799 --- /dev/null +++ b/rooter/0splash/status/files/usr/lib/lua/luci/controller/splashset.lua @@ -0,0 +1,11 @@ +--[[ +luci-app-argon-config +]]-- + +module("luci.controller.splash", package.seeall) + +function index() + if nixio.fs.access("/etc/config/splash") then + entry({"admin", "theme", "splash"}, cbi("splash"), _("Splash Screen"), 71) + end +end diff --git a/rooter/0splash/status/files/usr/lib/lua/luci/model/cbi/splash.lua b/rooter/0splash/status/files/usr/lib/lua/luci/model/cbi/splash.lua new file mode 100644 index 0000000..b36dc8b --- /dev/null +++ b/rooter/0splash/status/files/usr/lib/lua/luci/model/cbi/splash.lua @@ -0,0 +1,22 @@ +local fs = require "nixio.fs" +local sys = require "luci.sys" +local uci = require "luci.model.uci".cursor() +require("luci.util") +require("luci.model.ipkg") + +local m = Map("splash", translate("Splash Screen"), translate("Enable/disable Splash Screen")) + +m.on_after_save = function(self) + luci.sys.call("/usr/lib/splash/splash.sh &") +end + +gwx = m:section(TypedSection, "settings", translate("Management")) +gwx.anonymous = true + + +bl = gwx:option(ListValue, "enabled", "Enable Splash Screen :"); +bl:value("0", "Disabled") +bl:value("1", "Enabled") +bl.default=0 + +return m \ No newline at end of file diff --git a/rooter/0splash/status/files/usr/lib/splash/check.gif b/rooter/0splash/status/files/usr/lib/splash/check.gif new file mode 100644 index 0000000000000000000000000000000000000000..75b945d2553848b8b6f41fe5e24599c0687b8472 GIT binary patch literal 49 zcmZ?wbhEHbWMp7unE0RJ|Ns9C3=9Vj8~~DvKUo+V7?>DzfNY>Fh|Ltj$Y2csQN9XW literal 0 HcmV?d00001 diff --git a/rooter/0splash/status/files/usr/lib/splash/full.gif b/rooter/0splash/status/files/usr/lib/splash/full.gif new file mode 100644 index 0000000000000000000000000000000000000000..75b945d2553848b8b6f41fe5e24599c0687b8472 GIT binary patch literal 49 zcmZ?wbhEHbWMp7unE0RJ|Ns9C3=9Vj8~~DvKUo+V7?>DzfNY>Fh|Ltj$Y2csQN9XW literal 0 HcmV?d00001 diff --git a/rooter/0splash/status/files/usr/lib/splash/splash.sh b/rooter/0splash/status/files/usr/lib/splash/splash.sh new file mode 100644 index 0000000..6b1cca7 --- /dev/null +++ b/rooter/0splash/status/files/usr/lib/splash/splash.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +log() { + logger -t "Splash Screen : " "$@" +} + +sleep 5 + +ENB=$(uci get splash.settings.enabled) +FULL=$(uci get splash.settings.full) + +if [ $ENB = "0" ]; then + rm -f /www/splash_files/check.gif + rm -f /www/splash_files/full.gif +else + cp /usr/lib/splash/check.gif /www/splash_files + rm -f /www/splash_files/full.gif + if [ $FULL = "1" ]; then + cp /usr/lib/splash/full.gif /www/splash_files + fi +fi \ No newline at end of file diff --git a/rooter/0splash/status/files/www/luci-static/rooter/css/iconmoon_splash.css b/rooter/0splash/status/files/www/luci-static/rooter/css/iconmoon_splash.css new file mode 100644 index 0000000..5254b92 --- /dev/null +++ b/rooter/0splash/status/files/www/luci-static/rooter/css/iconmoon_splash.css @@ -0,0 +1,69 @@ +@font-face { + font-family: 'icomoon_splash'; + src: url('../fonts/icomoon_splash.eot?vja16g'); + src: url('../fonts/icomoon_splash.eot?vja16g#iefix') format('embedded-opentype'), + url('../fonts/icomoon_splash.ttf?vja16g') format('truetype'), + url('../fonts/icomoon_splash.woff?vja16g') format('woff'), + url('../fonts/icomoon_splash.svg?vja16g#icomoon_splash') format('svg'); + font-weight: normal; + font-style: normal; +} + +[class^="icon-"], [class*=" icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'icomoon_splash' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + + +.icon-power-off:before { + content: "\f011"; +} +.icon-signal:before { + content: "\f012"; +} +.icon-cog:before { + content: "\f013"; +} +.icon-gear:before { + content: "\f013"; +} +.icon-home:before { + content: "\f015"; +} +.icon-exclamation-triangle:before { + content: "\f071"; +} +.icon-warning:before { + content: "\f071"; +} +.icon-comments:before { + content: "\f086"; +} +.icon-hdd-o:before { + content: "\f0a0"; +} +.icon-plug:before { + content: "\f1e6"; +} +.icon-wifi:before { + content: "\f1eb"; +} +.icon-connection:before { + content: "\e91b"; +} +.icon-podcast:before { + content: "\e91c"; +} +.icon-earth:before { + content: "\e9ca"; +} diff --git a/rooter/0splash/status/files/www/luci-static/rooter/css/splash.css b/rooter/0splash/status/files/www/luci-static/rooter/css/splash.css new file mode 100644 index 0000000..bafcc6c --- /dev/null +++ b/rooter/0splash/status/files/www/luci-static/rooter/css/splash.css @@ -0,0 +1,311 @@ +/* @override http://src.dev.lo.lo/ROOter/www/luci-static/rooter/css/splash.css */ + +/* + CSS for ROOter splash pages + Copyright Francois Dechery + https://github.com/soif +*/ + +/* @group Splash Pages +--------------------------------------------------*/ + +.rooterSplash{ + padding: 0; + background: #F0F0F0; +} +.rooterPageHead{ + background: #55F; + padding: 10px 5px; + background: rgb(140,140,255); + background: -moz-linear-gradient(top, rgba(140,140,255,1) 0%, rgba(85,85,255,1) 100%); + background: -webkit-linear-gradient(top, rgba(140,140,255,1) 0%,rgba(85,85,255,1) 100%); + background: linear-gradient(to bottom, rgba(140,140,255,1) 0%,rgba(85,85,255,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#8c8cff', endColorstr='#5555ff',GradientType=0 ); + border-bottom: 1px solid rgba(0,0,0,0.7); + +} +.rooterPageContent{ + border-top: 1px solid rgba(255,255,255,0.8); + border-bottom: 1px solid rgba(0,0,0, 0.1); + padding: 25px 10px; + max-width: 1200px; + margin: auto; +} +.rooterHeadTitle{ + color: #fff; + text-align: center; + font-family: Georgia, "Times New Roman", Times, serif; + font-size: 32px; + line-height: 120%; + text-shadow: -1px -1px 2px rgba(0,0,0,0.5); +} +.rooterPageFoot{ + border-top: 1px solid rgba(255,255,255,0.8); + margin-top: 20px; + padding: 10px 10px; + max-width: 950px; + margin: auto; + font-size: 16px; +} +.rooterFootMenu{ + float: left; + margin-bottom: 10px; +} +.rooterFootMenu A{ + text-decoration: none; +} +.rooterFootMenu A:hover{ + color: #000; +} +.rooterFootMenu UL{ + padding: 0; + margin: 0; + overflow: hidden; + display: inline-block; +} +.rooterFootMenu LI{ + float: left; + padding: 0; + margin: 0; + list-style: none; +} +.rooterFootMenu LI A{ + padding: 0 10px; + color: #555; +} +.rooterFootMenu LI:first-child A{ + padding-left: 0; +} +.rooterFootCredits{ + float: right; + padding: 0; + margin: 0; + color: #999; + text-align: right; +} +.rooterFootCredits A{ + color: #777; +} +/* @end */ + + + + +/* @group Page: Home +--------------------------------------------------*/ + + +/* @group Logo +++++++++++++++++++ */ +.rooterHeadBox{ + font-size: 50px; + font-family: Georgia, "Times New Roman", Times, serif; + color: #fff; + line-height: 100%; + overflow: hidden; + width: 700px; + margin: auto; + padding-top: 10px; + opacity: 0; +} +.rooterLogo{ + background: url("../img/kangaroo_800.png") no-repeat; + background-size: 100%; + float: left; + height: 110px; + width: 250px; + opacity: 0.4; +} +.rooterTagline{ + margin-left: 100px; + padding-left: 10px; + text-shadow: 2px 2px 3px rgba(0,0,0,0.3); +} + +/* @end */ + +@media only screen and (max-width: 600px) { + .rooterHeadBox{ + text-align: center; + width: auto; + } + .rooterLogo{ + display: inline-block; + float: none; + } + .rooterTagline { + display: none; + } + .rooterFootCredits, + .rooterFootMenu{ + float: none; + text-align: center; + } +} + +#rooterItems{ + clear: both; + max-width: 800px ; + margin: auto; +} +.rooterItem{ + overflow: hidden; + border: 1px solid #EEE; + border-color: #EEE #DDD #DDD #EEE; + padding: 20px 15px; + margin-bottom: 20px; + border-radius: 8px; + background-color: #fff; +} +.rooterItem:hover{ + background-color: #F3F3FF; + border-color: #AAA; +} +.rooterItemTitle{ + float: left; + font-size: 18px; + font-weight: bold; + padding-right: 10px; + color: #000; + line-height: 2em; +} +.rooterItemTitle .icon{ + color: #55F; + margin-right: 8px; + font-size: 2em; + vertical-align: middle; +} +#rooterItems A{ + text-decoration: none; +} +.rooterItemDesc{ + font-size: 14px; + color: #777; + margin-left: 220px; + margin-top: 0.7em; +} +/* @end */ + + + +/* @group Page: Status +--------------------------------------------------*/ + +.modemStatusBlock{ + margin-bottom: 30px; +} +#rooterSplashStatus h3{ + clear:both; + font-size: 18px; + color: #55F; +} +#rooterSplashStatus h3 .icon{ + margin-right: 3px; +} +#rooterSplashStatus h3 .msCell{ + color: #666; +} +.modemStatusRow{ + clear:both; + padding-bottom: 20px; + overflow: hidden; +} +.modemStatusRow .msTitle{ + border-radius: 2px 2px 0 0; + padding: 5px 5px ; + background: #484848; + color: #fff; + background: rgb(99,99,99); + background: -moz-linear-gradient(top, rgba(99,99,99,1) 0%, rgba(72,72,72,1) 100%); + background: -webkit-linear-gradient(top, rgba(99,99,99,1) 0%,rgba(72,72,72,1) 100%); + background: linear-gradient(to bottom, rgba(99,99,99,1) 0%,rgba(72,72,72,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#636363', endColorstr='#484848',GradientType=0 ); +} +.modemStatusRow .msCell{ + border-radius: 10px; + display: inline-block; + margin-top: 10px; + float:left; + border: 1px solid #ccc; + padding-bottom: 5px; + background: #fff; + +} +.modemStatusRow1 .msCell{ + width: 176px; + margin: 10px 5px 0 5px; + text-align: center; +} +.modemStatusRow1 SPAN B{ + font-weight: bold; + font-size: 70px; + line-height: 110%; + text-shadow: 1px 1px 1px rgba(0,0,0,0.4); +} +.modemStatusRow1 .msDesc{ + color: #000; + font-size: 12px; +} +.modemStatusRow2 .msCell{ + margin: 10px 5px; + text-align: center; +} +.modemStatusRow2 SPAN{ + display: inline-block; + padding: 5px 5px ; + font-size: 14px; +} +#counter_div{ + color: #000; + font-weight: normal; + font-size: 14px; +} +#counter_val{ + color: #F00; + font-size: 32px; + font-weight: bold; + text-shadow: 1px 1px 1px rgba(0,0,0,0.1); +} +#msCell_per{} +#msCell_csq{} +#msCell_rssi{} +#msCell_rscp{} +#msCell_ecio{} + +#rooterSplashStatus .level_0{ + color: #0F0; // green +} +#rooterSplashStatus .level_1{ + color: #0CB; // green blue +} +#rooterSplashStatus .level_2{ + color: #00F; // blue +} +#rooterSplashStatus .level_3{ + color: #F0F; // violet +} +#rooterSplashStatus .level_4{ + color: #F80; // orange +} +#rooterSplashStatus .level_5{ + color: #F00; // red +} +#rooterSplashStatus .level_6{ + color: #FF0; // yellow +} + +/* @end */ + + +/* Easy Color changer ------------- */ + +.rooterPageHead{ + /*background: #55F;*/ +} +.rooterItemTitle .icon, +#rooterSplashStatus h3{ + color: #55F; +} + + + diff --git a/rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.eot b/rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.eot new file mode 100644 index 0000000000000000000000000000000000000000..29cd4d1f36a419b4822d210be985dbde03d1d3ac GIT binary patch literal 4708 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 Gn*ReFo8=Jz literal 0 HcmV?d00001 diff --git a/rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.svg b/rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.svg new file mode 100644 index 0000000..dc2127b --- /dev/null +++ b/rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.svg @@ -0,0 +1,22 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.ttf b/rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4e27645c4f897ba62acace85a644aff591860682 GIT binary patch literal 4516 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 E0b}jXx&QzG literal 0 HcmV?d00001 diff --git a/rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.woff b/rooter/0splash/status/files/www/luci-static/rooter/fonts/icomoon_splash.woff new file mode 100644 index 0000000000000000000000000000000000000000..63f541307f5f723c6eed5ef792b2fbce8e4ea0f7 GIT binary patch literal 4592 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 Vg5RoPjlsG#(%?z@pM}q8{|Cw&)JOmT literal 0 HcmV?d00001 diff --git a/rooter/0splash/status/files/www/luci-static/rooter/img/favicon.gif b/rooter/0splash/status/files/www/luci-static/rooter/img/favicon.gif new file mode 100644 index 0000000000000000000000000000000000000000..bfbe292825c753540fdd42af7823e167398874e3 GIT binary patch literal 2441 zcmeH|`8yMi1ILGvYixGm<15Ef&K%XGWGY8nBu7{bHJZ6{Bq|yscV0Es=-6N-A(-ME%9Np_=t!2*uVA^pYRf&^oF*( z!kS&-EpG5uH*l{TxRV6!^#p$+f%{32esA!AJ7mBc^4SMD;Dwm+ z27mR1ehY+82SVo_AZCK0^C8fMhtQw*U`zLPrpg^~%uvH4| zR~USY0^6d(w<)k~Dq=SrwjF`kjeze(!gizJ`%%b)NW{S-BsU7a7me79g>z!yoLB@m z8qSS@AH>4BaR_d_>~^fmdYtMGUF{$RKa+-^Prtszyu;22{FEKml}G8$3+pfZFU$YO z{}=)J9UuHTLD06{K*D3&R(~8_?#haa^F?N!o zlsMu-tc*~Fu@K71ve@CNwg^8j>SkxAJ@sOYs-55BSd6OxPnr%@m}yrPk)mpvtnxqj0ew6D_ujjAtxs9Bikc{4)t`0#pbMT~G)cdhPSVxAf6tlIkb>#o#LkpANO z;*El?g2y5AzgOIAzHw*8vYrPu&2+urXN7WtTbHZ$vY6*WO*c1xHrYBD7#QszaOw^d z>-k?yKIn&&oQ(h)c6}6<@_hD1kok~BBm&DXe_Lv#M&9c`gl(6H@=6gdF#^nJ1w$3q zF^f2j*81G|V|}KX5S#M+Z&*1Q;?3Je^O(1f)qK|s!wi010}AN{OwS}+=n3)Nx%9mj zCD!EF!keOq9hyk7_l_Yxfrjs7q@ANLWIrvxrrz?4nF=Hb1PTZ#U53oQz)4~-1p@N; zl-%RmD#L{+P3~F-*dPZ_E5=pqCNeErR6IPYv&hQNy~w*#g~dC19;I!M+<*AU-NT-L z*(IE@SkUvhVIhdg`&_NOn}GX~+1vMJnJ~$Mzbpk#7c*F|l^AccH-v>Fqy-9apI?1& zD_*V`Gd@DhSLNKsNbi{MmAsmsh%Ie$_l}!rKqS#FzzM{cYwrlhd;vUy$b28${n!kz zcEA-GxR4@dZB&eplBroUgQrx%@n-`Q9Bew!&-S0UuNuCs>?&B_p0{s(0hOWAe)8jP-l7 zm9g(i8~0aBK~87;bLP}PPGEnJ?@yK#v$U6*MXv164IM7y7>pgA4H@d06Xo>GST&{o zp7-HwZzdi0(OV?q?EA#D_17J*JgnbKU&(skIL{sIrR=ng9t?dkpubtZpE7DSEQosZ z%jV|;!6HXnZ}h8Lds^@+pA)McjrsQ&sD~KNytq2d&PiG*aAS&t2?9f|MMiY!On=l! zYZcWXQz47l9CmmUSlTCoP0jpezTLFV;~g5_H7(KD*DiZ*E$ZsbBrGbrwclRrft>>r zAwS=~VdxvOe4%r%`$g;BijSUHVjgl_&{+2xE#Bs3-rx$m^S7uIr(ODA>bOQRd!76+^)JBhkVD(k)@2uP$fz8W(i z=w7z%1g8o!W>-kVjc05963awysKuSabrsQ1jkO=qnyl|42lg_Wtlc!97MYNKT}=x;&gqW3TbnA}QSS95oj9!b!RS?JE&sX zfbY3Z56Hsl7oD^se@eN*D7{-YPSQFF9%R>M7)=@9+TG+iloJO0ao-8aJR%1;^ACjV#SQ=f literal 0 HcmV?d00001 diff --git a/rooter/0splash/status/files/www/luci-static/rooter/img/kangaroo_800.png b/rooter/0splash/status/files/www/luci-static/rooter/img/kangaroo_800.png new file mode 100644 index 0000000000000000000000000000000000000000..478fa6d62f4ce758358142fefd480c564773ce36 GIT binary patch literal 5836 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 Wk|dU(LN#0f0000 + + + Live Network Status + + + + + + + + + + + + + + + +
                          +
                          ROOter Live Network Status
                          +
                          + +
                          + + + + + + + +
                          Enter your password :
                          + + + +
                          +

                          0 sec
                          + Signal

                          + +
                          +
                          +
                          Strength (%)
                          + - +
                          +
                          +
                          CSQ
                          + - +
                          +
                          +
                          RSSI (dBm)
                          + - +
                          +
                          +
                          RSCP (dBm) RSRP
                          + - +
                          +
                          +
                          ECIO (dB) RSRQ
                          + - +
                          +
                          +
                          SINR (dB)
                          + - +
                          +
                          +
                          + +
                          +

                          Network -

                          + +
                          +
                          +
                          Mode
                          + - +
                          +
                          +
                          MCC
                          + - +
                          +
                          +
                          MNC
                          + - +
                          +
                          +
                          RNC/eNB ID
                          + - - +
                          + +
                          +
                          LAC
                          + - - +
                          +
                          +
                          Cell ID
                          + - +
                          +
                          +
                          Channel
                          + - +
                          +
                          +
                          Bands
                          + - +
                          +
                          +
                          + +
                          +

                          Device -

                          + +
                          +
                          +
                          Modem
                          + - +
                          +
                          +
                          Protocol
                          + - +
                          +
                          +
                          Port
                          + - +
                          +
                          +
                          Temperature
                          + - +
                          +
                          +
                          + +
                          + +
                          +
                          + ROOter Splash Page by Soif and Dairyman +
                          +
                          + + + diff --git a/rooter/0splash/status/files/www/splash_files/cellular.png b/rooter/0splash/status/files/www/splash_files/cellular.png new file mode 100644 index 0000000000000000000000000000000000000000..953bf0897143d03cca60de20b753e2159dbf6927 GIT binary patch literal 8344 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 literal 0 HcmV?d00001 diff --git a/rooter/0splash/status/files/www/splash_files/forum.png b/rooter/0splash/status/files/www/splash_files/forum.png new file mode 100644 index 0000000000000000000000000000000000000000..9e8b8c222e46c082eb0bed1621b309f7144d12fe GIT binary patch literal 3845 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 literal 0 HcmV?d00001 diff --git a/rooter/0splash/status/files/www/splash_files/home.png b/rooter/0splash/status/files/www/splash_files/home.png new file mode 100644 index 0000000000000000000000000000000000000000..38687c71991b5ed5e17625142388a46dde396ebc GIT binary patch literal 1262 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 literal 0 HcmV?d00001 diff --git a/rooter/0splash/status/files/www/splash_files/rooter.png b/rooter/0splash/status/files/www/splash_files/rooter.png new file mode 100644 index 0000000000000000000000000000000000000000..be8099f6b2dd0206a37ee4a6313f3ada97a08528 GIT binary patch literal 311293 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�$6Fa*?Ro&;ozxP$*s2vB9{D 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�!$5oK1*okxLp=Cj1|cI(jc%`*jn;VPZzn^BB|qX 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 literal 0 HcmV?d00001 diff --git a/rooter/0splash/status/files/www/splashfull.html b/rooter/0splash/status/files/www/splashfull.html new file mode 100644 index 0000000..1624809 --- /dev/null +++ b/rooter/0splash/status/files/www/splashfull.html @@ -0,0 +1,101 @@ + + + + Home - ROOter + + + + + + + + + + + + + + + + + + + +

                          + +
                          + +
                          The ROOter Project
                          +
                          +
                          + +
                          + +
                          +
                          + +
                          +
                          + ROOter Splash Page by Soif and Dairyman +
                          +
                          + + + + diff --git a/rooter/0splash/status/files/www/statusfull.html b/rooter/0splash/status/files/www/statusfull.html new file mode 100644 index 0000000..6e37899 --- /dev/null +++ b/rooter/0splash/status/files/www/statusfull.html @@ -0,0 +1,271 @@ + + + + Live Network Status + + + + + + + + + + + + + + + +
                          +
                          ROOter Live Network Status
                          +
                          + +
                          + + + + + + + +
                          Enter your password :
                          + + + +
                          +

                          0 sec
                          + Signal

                          + +
                          +
                          +
                          Strength (%)
                          + - +
                          +
                          +
                          CSQ
                          + - +
                          +
                          +
                          RSSI (dBm)
                          + - +
                          +
                          +
                          RSCP (dBm) RSRP
                          + - +
                          +
                          +
                          ECIO (dB) RSRQ
                          + - +
                          +
                          +
                          SINR (dB)
                          + - +
                          +
                          +
                          + +
                          +

                          Network -

                          + +
                          +
                          +
                          Mode
                          + - +
                          +
                          +
                          MCC
                          + - +
                          +
                          +
                          MNC
                          + - +
                          +
                          +
                          RNC/eNB ID
                          + - - +
                          + +
                          +
                          LAC
                          + - - +
                          +
                          +
                          Cell ID
                          + - +
                          +
                          +
                          Channel
                          + - +
                          +
                          +
                          Bands
                          + - +
                          +
                          +
                          + +
                          +

                          Device -

                          + +
                          +
                          +
                          Modem
                          + - +
                          +
                          +
                          Protocol
                          + - +
                          +
                          +
                          Port
                          + - +
                          +
                          +
                          Temperature
                          + - +
                          +
                          +
                          + +
                          + +
                          +
                          + +
                          +
                          + ROOter Splash Page by Soif and Dairyman +
                          +
                          + + + diff --git a/rooter/ext-rooter-basic/Makefile b/rooter/ext-rooter-basic/Makefile new file mode 100644 index 0000000..6e5e0ba --- /dev/null +++ b/rooter/ext-rooter-basic/Makefile @@ -0,0 +1,43 @@ +#Owned by DairyMan@Whirlpool +# +#Copyright GNU act. +include $(TOPDIR)/rules.mk + +PKG_NAME:=ext-rooter-basic +PKG_VERSION:=4.500 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool +include $(INCLUDE_DIR)/package.mk + +# +kmod-rt2800-usb + +define Package/ext-rooter-basic + SECTION:=utils + CATEGORY:=ROOter + SUBMENU:=Basic Support + DEPENDS:=+luci-compat +kmod-usb-net +kmod-usb-net-huawei-cdc-ncm +kmod-usb-net-cdc-ether +kmod-usb-acm \ + +kmod-usb-net-qmi-wwan +kmod-usb-net-rndis +kmod-usb-serial-qualcomm \ + +kmod-usb-net-sierrawireless +kmod-usb-ohci +kmod-usb-serial +kmod-nls-utf8 \ + +kmod-usb-serial-option +kmod-usb-serial-sierrawireless +luci-proto-3x \ + +kmod-usb-uhci +kmod-usb2 +luci-proto-3g \ + +usb-modeswitch +wireless-tools +rmbim +rqmi +ext-sms +ext-buttons +luci-app-pcimodem + TITLE:=ROOter support for usbmodems + PKGARCH:=all +endef + +define Package/ext-rooter-basic/description + Helper scripts to enable ROOter to manage usb modem interfaces +endef + + +define Build/Compile +endef + +define Package/ext-rooter-basic/install + $(CP) ./files/* $(1)/ + + +endef + +$(eval $(call BuildPackage,ext-rooter-basic)) diff --git a/rooter/ext-rooter-basic/files/etc/codename b/rooter/ext-rooter-basic/files/etc/codename new file mode 100644 index 0000000..252dcda --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/codename @@ -0,0 +1 @@ +CODENAME="GoldenOrb-Version-1" \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/etc/config/custom b/rooter/ext-rooter-basic/files/etc/config/custom new file mode 100644 index 0000000..67d0a8e --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/config/custom @@ -0,0 +1,64 @@ + +config bwallocate 'bwallocate' + option rollover '1' + option allocate '1000' + option password '1234' + option lock '0' + option enabled '0' + +config texting 'texting' + option text '0' + option phone '1222333444' + option time '72' + option ident 'John Doe' + option method '0' + option days '1' + option increment '50' + option used '0' + option tore '0' + +config menu 'menu' + option password '1234' + option full '0' + option enabled '0' + option default '0' + +config atcmd 'atcmd' + option lock '0' + option enabled '1' + option password '1234' + option sierra '/etc/sierracmd' + option quectel '/etc/quectelcmd' + option generic '/etc/genericcmd' + +config bandlock 'bandlock' + option enabled '1' + option cenable1 '0' + option earfcn1 '0' + option pci1 '0' + +config zerotier 'zerotier' + option password '1234' + option lock '0' + option networkid 'xxxxxxxxxxxxxxxx' + +config logo 'logo' + option size 'large' + +config connect 'connect' + option ipv6 '1' + +config profile 'profile' + option save '0' + +config multi 'multiuser' + option multi '0' + option root '0' + +config bwday 'bwday' + option bwday '0' + option phone '0' + option delay '8' + +config simpin 'simpin' + option pin '' \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/etc/config/modem b/rooter/ext-rooter-basic/files/etc/config/modem new file mode 100644 index 0000000..617a570 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/config/modem @@ -0,0 +1,18 @@ + +config info 'general' + option modemnum '1' + option max '6' + +config new 'customize' + +config modem 'modem1' + option empty '1' + +config minfo1 'modeminfo1' + +config modem 'modem2' + option empty '1' + +config minfo2 'modeminfo2' + + diff --git a/rooter/ext-rooter-basic/files/etc/config/profile b/rooter/ext-rooter-basic/files/etc/config/profile new file mode 100644 index 0000000..d383cad --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/config/profile @@ -0,0 +1,19 @@ + +config default 'default' + option auth '0' + option ppp '0' + option lock '0' + option log '0' + option lb '1' + option alive '0' + option delay '5' + option at '0' + option apn '3gnet' + option tzone '0' + option nodhcp '0' + option pdptype '0' + +config disable 'disable' + option enabled '0' + +config simpin 'simpin' diff --git a/rooter/ext-rooter-basic/files/etc/config/ttl b/rooter/ext-rooter-basic/files/etc/config/ttl new file mode 100644 index 0000000..e7e7367 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/config/ttl @@ -0,0 +1,11 @@ + +config ttl 'ttl' + option enabled '0' + option value '65' + +config hotspot 'hotspot' + option enable '0' + option oldenable '0' + option amt '10000' + option total '0' + diff --git a/rooter/ext-rooter-basic/files/etc/config/variable b/rooter/ext-rooter-basic/files/etc/config/variable new file mode 100644 index 0000000..5755430 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/config/variable @@ -0,0 +1,4 @@ + config info 'info' + option smssleep '20' + option buffersize '50' + \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/etc/genericcmd b/rooter/ext-rooter-basic/files/etc/genericcmd new file mode 100644 index 0000000..b6b15bc --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/genericcmd @@ -0,0 +1,4 @@ +AT+CRSM=176,12258,0,0,10 +ICCID +at+csq +Signal Information diff --git a/rooter/ext-rooter-basic/files/etc/header_msg b/rooter/ext-rooter-basic/files/etc/header_msg new file mode 100644 index 0000000..e3f2398 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/header_msg @@ -0,0 +1,4 @@ + +/img/header.png +/img/rosy.png +/img/tomato.png \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/etc/hotplug.d/iface/10-lan b/rooter/ext-rooter-basic/files/etc/hotplug.d/iface/10-lan new file mode 100644 index 0000000..3512e42 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/hotplug.d/iface/10-lan @@ -0,0 +1,27 @@ +#!/bin/sh + +logger -t URL-DEBUG "hotplug (iface): action='$ACTION' interface='$INTERFACE'" + +if [ "$ACTION" = ifup -a "$INTERFACE" = "lan" ]; then + IP=$(uci get network.lan.ipaddr) + ipaddr=$(cat /etc/dnsmasq.conf | grep "address=/rooter.local/") + if [ ! -z $ipaddr ]; then + ipaddr=$(echo "$ipaddr" | sed -e "s!address=/rooter.local/!!g") + if [ $ipaddr != $IP ]; then + cp -f /etc/dnsmasq.conf /etc/dnsmasq.conf.bk + sed /"#StartURL"/,/"#EndURL"/d /etc/dnsmasq.conf.bk > /etc/dnsmasq.conf + rm -f /etc/dnsmasq.conf.bk + echo "#StartURL" >> /etc/dnsmasq.conf + echo "address=/rooter.local/$IP" >> /etc/dnsmasq.conf + echo "address=/www.rooter.local/$IP" >> /etc/dnsmasq.conf + echo "#EndURL" >> /etc/dnsmasq.conf + /etc/init.d/dnsmasq restart + fi + else + echo "#StartURL" >> /etc/dnsmasq.conf + echo "address=/rooter.local/$IP" >> /etc/dnsmasq.conf + echo "address=/www.rooter.local/$IP" >> /etc/dnsmasq.conf + echo "#EndURL" >> /etc/dnsmasq.conf + /etc/init.d/dnsmasq restart + fi +fi \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/etc/hotplug.d/iface/19-rooter b/rooter/ext-rooter-basic/files/etc/hotplug.d/iface/19-rooter new file mode 100644 index 0000000..e0ecea9 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/hotplug.d/iface/19-rooter @@ -0,0 +1,42 @@ +#!/bin/sh +# +# /etc/hotplug.d/iface/19-rooter +# + +log() { + logger -t "19-ROOTER" "$@" +} + +for I in `seq 1 $(uci get modem.general.modemnum)` +do + IFACE="wan"$I + + [ "$ACTION" = ifup -o "$ACTION" = ifupdate ] || exit 0 + if [ ${INTERFACE} = "$IFACE" ]; then + if [ ${ACTION} = "ifup" ]; then + # TTL fix + if [ 1 = 0 ]; then + ttl=$(uci -q get modem.modeminfo$I.ttl) + if [ -z $ttl ]; then + ttl=0 + fi + if [ $ttl -eq 0 ]; then + ENB=$(uci get ttl.ttl.enabled) + if [ ! -z "$ENB" ]; then + #exst=$(cat /etc/firewall.user | grep " mangle .* $DEVICE " | wc -l) + #[ "$exst" -eq 4 ] || /usr/lib/custom/ttlx.sh + /usr/lib/custom/ttlx.sh + fi + fi + fi + MTU=$(uci get modem.modeminfo$I.mtu) + if [ -z $MTU ]; then + MTU=1500 + fi + if [ -n "$MTU" ]; then + ip link set mtu $MTU dev $DEVICE + logger -t "Custom MTU" $DEVICE set to $MTU + fi + fi + fi +done diff --git a/rooter/ext-rooter-basic/files/etc/hotplug.d/tty/30-3x b/rooter/ext-rooter-basic/files/etc/hotplug.d/tty/30-3x new file mode 100644 index 0000000..664d4ae --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/hotplug.d/tty/30-3x @@ -0,0 +1,31 @@ +#!/bin/sh +. /lib/functions.sh +. /lib/netifd/netifd-proto.sh + +find_3g_iface() { + local cfg="$1" + local tty="$2" + local proto + config_get proto "$cfg" proto + [ "$proto" = 3x ] || return 0 + + # bypass state vars here because 00-netstate could clobber .device + local dev=$(uci_get network "$cfg" device) + if [ "${dev##*/}" = "${tty##*/}" ]; then + if [ "$ACTION" = add ]; then + available=1 + else + available=0 + fi + proto_set_available "$cfg" $available + fi +} + +case "$DEVICENAME" in + tty*) + [ -e "/dev/$DEVICENAME" ] || [ "$ACTION" = remove ] || exit 0 + config_load network + config_foreach find_3g_iface interface "/dev/$DEVICENAME" + ;; +esac + diff --git a/rooter/ext-rooter-basic/files/etc/hotplug.d/usb/20-usb_mode b/rooter/ext-rooter-basic/files/etc/hotplug.d/usb/20-usb_mode new file mode 100644 index 0000000..aef0620 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/hotplug.d/usb/20-usb_mode @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/lib/rooter/modeswitch.sh & \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/etc/init.d/clear b/rooter/ext-rooter-basic/files/etc/init.d/clear new file mode 100644 index 0000000..a924aaa --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/init.d/clear @@ -0,0 +1,21 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +START=19 + +start() { + COUNTER=1 + while [ $COUNTER -le 5 ]; do + INEX=$(uci -q get network.wan$COUNTER) + if [ -z $INEX ]; then + break + else + uci delete network.wan$COUNTER + uci commit network + fi + let COUNTER=COUNTER+1 + done + uci delete network.wg0 + uci delete network.wg1 + uci commit network +} diff --git a/rooter/ext-rooter-basic/files/etc/init.d/iphone b/rooter/ext-rooter-basic/files/etc/init.d/iphone new file mode 100644 index 0000000..625b1e0 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/init.d/iphone @@ -0,0 +1,22 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +START=95 + +start() { + if [ ! -d "/var/lib/lockdown" ];then + mkdir -p /var/lib/lockdown + fi + bkp_files=`ls /etc/lockdown/locks` + for file in $bkp_files; + do + if [ ! -f "/var/lib/lockdown/$file" ];then + cp /etc/lockdown/locks/$file /var/lib/lockdown/ + fi + done + proc_usbmuxd=`ps | grep usbmuxd` + nb_usbmuxd=`echo "$proc_usbmuxd" | grep /usr/sbin/usbmuxd | wc -l` + if [ ! "$nb_usbmuxd" -eq 1 ];then + [ -x /usr/sbin/usbmuxd ] && usbmuxd -v + fi +} \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/etc/init.d/rooter b/rooter/ext-rooter-basic/files/etc/init.d/rooter new file mode 100644 index 0000000..1199b98 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/init.d/rooter @@ -0,0 +1,9 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +START=99 + +start() { + /usr/lib/rooter/initialize.sh +} + diff --git a/rooter/ext-rooter-basic/files/etc/init.d/usbmode b/rooter/ext-rooter-basic/files/etc/init.d/usbmode new file mode 100644 index 0000000..441b70a --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/init.d/usbmode @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2013 OpenWrt.org + +START=88 +USE_PROCD=1 + +log() { + logger -t "usb-modeswitch" "$@" +} + +start_service() +{ + log "Remove early Modeswitch" +} diff --git a/rooter/ext-rooter-basic/files/etc/lockdown/locks/0000000000000000000000000000000000000000.plist b/rooter/ext-rooter-basic/files/etc/lockdown/locks/0000000000000000000000000000000000000000.plist new file mode 100644 index 0000000..e69de29 diff --git a/rooter/ext-rooter-basic/files/etc/netspeed b/rooter/ext-rooter-basic/files/etc/netspeed new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/netspeed @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/etc/newstyle b/rooter/ext-rooter-basic/files/etc/newstyle new file mode 100644 index 0000000..e69de29 diff --git a/rooter/ext-rooter-basic/files/etc/quectelcmd b/rooter/ext-rooter-basic/files/etc/quectelcmd new file mode 100644 index 0000000..a87e3b5 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/quectelcmd @@ -0,0 +1,6 @@ +AT+CRSM=176,12258,0,0,10 +ICCID +AT+QMBNCFG="AutoSel",0 +APNFIX#1 +AT+QMBNCFG="Deactivate" +APNFIX#2 diff --git a/rooter/ext-rooter-basic/files/etc/sierracmd b/rooter/ext-rooter-basic/files/etc/sierracmd new file mode 100644 index 0000000..d62aaa1 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/sierracmd @@ -0,0 +1,4 @@ +AT+CRSM=176,12258,0,0,10 +ICCID +at+csq +Signal Strength diff --git a/rooter/ext-rooter-basic/files/etc/ttl.user b/rooter/ext-rooter-basic/files/etc/ttl.user new file mode 100644 index 0000000..98707a2 --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/ttl.user @@ -0,0 +1,4 @@ +# +# TTL Setting +# + diff --git a/rooter/ext-rooter-basic/files/etc/usb-mode.json b/rooter/ext-rooter-basic/files/etc/usb-mode.json new file mode 100644 index 0000000..90a68be --- /dev/null +++ b/rooter/ext-rooter-basic/files/etc/usb-mode.json @@ -0,0 +1,3180 @@ +{ + "messages" : [ + "555342431234567800000000000006d0000000000000000000000000000000", + "55534243123456780002000000000a2a000000003300000100000000000000", + "5553424312345678000000000000061b004600000000000000000000000000", + "0f00010142", + "55534243f0298d8124000000800006bc626563240000000000000000000000", + "0902200001010080fa0904000002080650000705010200020007058102000200", + "55534243785634120100000080000601000000000000000000000000000000", + "55534243123456780000000000000616000000000000000000000000000000", + "55534243123456782400000080000612000024000000000000000000000000", + "5553424312345678000000000000061b000000ff0000000000000000000000", + "5553424368032c882400000080000612000000240000000000000000000000", + "5553424308306384c000000080000671030000000000000000000000000000", + "5553424312345678c00000008000069f140000000000000000000000000000", + "01b0000000000000000000000000000000000000000000000000000000000000", + "555342431234567800000000000006bd000000020000000000000000000000", + "1b5a01", + "5553424312345678c000000080010606f50402527000000000000000000000", + "55534243123456788000000080000606f50402527000000000000000000000", + "555342431234567800000000000006f0010300000000000000000000000000", + "55534243123456780000000000000aff554d53434847000000000000000000", + "555342431234567803000000800006f1010100000000000000000000000000", + "555342431234567800000000000005f1010100000000000000000000000000", + "555342431234567824000000800008ff024445564348470000000000000000", + "555342431234567824000000800008ff020000000000000000000000000000", + "55534243b82e238c24000000800008ff020000000000000000000000000000", + "55534243123456780600000080000601000000000000000000000000000000", + "55534243123456780600000080010a11060000000000000000000000000000", + "55534243123456780000000000000601000000000000000000000000000000", + "555342431234567824000000800008ff524445564348470000000000000000", + "555342431234567824000000800008ff524445564348473100000000000000", + "55534243123456782400000080000dfe524445564348473d4e444953000000", + "55534243d85dd88524000000800008ff524445564348470000000000000000", + "55534243123456702000000080000c85010101180101010101000000000000", + "55534243123456782400000080000685000000240000000000000000000000", + "55534243d8a523862400000080000685000000240000000000000000000000", + "5553424348c4758600000000000010ff000000000000000000000000000000", + "555342431234567824000000800006bc626563240000000000000000000000", + "5553424330f4cf8124000000800108df200000000000000000000000000000", + "5553424312345678c00000008000069f030000000000000000000000000000", + "555342431234567824000000800008FF05B112AEE102000000000000000000", + "55534243123456780000000000000606f50402527000000000000000000000", + "55534243123456780000000080000606f50402527000000000000000000000", + "555342431234567800000000000001ff000000000000000000000000000000", + "55534243123456781200000080000603000000020000000000000000000000", + "55534243123456780000000000000cff020000000000000000000000000000", + "5553424312345678800000008000060619181a207000000000000000000000", + "555342431234567800000000000010ff000000000000000000000000000000", + "555342431234567800000000000008ff000000000000030000000000000000", + "555342431234567824000000800108df200000000000000000000000000000", + "55534243f8d2e6838000000080000606f50402527000000000000000000000", + "555342431234567800000000000003f0010100000000000000000000000000", + "55534243123456780000000000000600000000000000000000000000000000", + "5553424312345679c000000080000671030000000000000000000000000000", + "555342430820298900000000000003f0010100000000000000000000000000", + "55534243123456700000000000000616aa0000000000000000000000000000", + "5553424312345678c000000080000671010000000000000000000000000000", + "5553424340799288C000000080010A16000000C00000000000000000000000", + "555342431234567800000000000006161f6d62706b00000000000000000000", + "5553424398e2c4812400000080000bff524445564348473d43440000000000" + ], + + "devices" : { + "03f0:002a": { + "*": { + "t_class": 7, + "msg": [ 0 ] + } + }, + "03f0:032a": { + "*": { + "t_class": 7, + "msg": [ 0 ] + } + }, + "03f0:371d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:4b1d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:4e1d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:521d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:531d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:541d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:581d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:631d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:641d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:681d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:911d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:931d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:9a1d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:9d1d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "03f0:a31d": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "0408:1000": { + "*": { + "t_vendor": 1032, + "t_product": [ 59906 ], + "msg": [ 1 ] + } + }, + "0408:ea17": { + "*": { + "t_vendor": 1032, + "t_product": [ 59926 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0408:ea43": { + "*": { + "t_vendor": 1032, + "t_product": [ 59975, 59977, 59981 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0408:f000": { + ":uMa=Yota": { + "t_vendor": 1032, + "t_product": [ 53257 ], + "msg": [ 2 ] + } + }, + "0421:060c": { + "*": { + "t_vendor": 1057, + "t_product": [ 1550 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0421:0610": { + "*": { + "t_vendor": 1057, + "t_product": [ 1554 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0421:0618": { + "*": { + "t_vendor": 1057, + "t_product": [ 1561 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0421:061d": { + "*": { + "t_vendor": 1057, + "t_product": [ 1566 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0421:0622": { + "*": { + "t_vendor": 1057, + "t_product": [ 1571 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0421:0627": { + "*": { + "t_vendor": 1057, + "t_product": [ 1554, 1577 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0421:062c": { + "*": { + "t_vendor": 1057, + "t_product": [ 1581, 1583 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0421:0632": { + "*": { + "t_vendor": 1057, + "t_product": [ 1586 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0421:0637": { + "*": { + "t_vendor": 1057, + "t_product": [ 1592 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "046d:c261": { + "*": { + "t_class": 3, + "msg_endpoint": 1, + "msg": [ 3 ], + "response_endpoint": 1 + } + }, + "0471:1210": { + ":uMa=Philips": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + }, + ":uMa=Wisue": { + "t_vendor": 7612, + "t_product": [ 5 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0471:1237": { + "*": { + "t_vendor": 1137, + "t_product": [ 4614, 4660 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0482:024d": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "04bb:bccd": { + "*": { + "t_vendor": 1211, + "t_product": [ 2377 ], + "msg": [ 4 ] + } + }, + "04cc:2251": { + "*": { + "t_vendor": 1228, + "t_product": [ 8793, 8814 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "04cc:225c": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "04cc:226e": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "04cc:226f": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "04e8:680c": { + "*": { + "t_vendor": 1256, + "t_product": [ 26514 ], + "msg": [ 5 ] + } + }, + "04e8:689a": { + "*": { + "t_vendor": 1256, + "t_product": [ 26761 ], + "msg": [ 6 ] + } + }, + "04e8:f000": { + ":sMo=U209": { + "t_vendor": 1256, + "t_product": [ 26113 ], + "msg": [ 7 ] + } + }, + "04fc:2140": { + "*": { + "t_vendor": 1276, + "t_product": [ 1557, 4672 ], + "msg": [ 8 ] + } + }, + "057c:62ff": { + "*": { + "t_vendor": 1404, + "t_product": [ 34049, 34050 ], + "msg": [ 9 ] + } + }, + "057c:84ff": { + "*": { + "t_vendor": 1404, + "t_product": [ 33793 ], + "msg": [ 9 ] + } + }, + "0586:2030": { + "*": { + "t_vendor": 1414, + "t_product": [ 13379, 13380 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "05c6:0010": { + "*": { + "t_vendor": 1478, + "t_product": [ 160 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "05c6:1000": { + ":uMa=AnyDATA": { + "t_vendor": 5845, + "t_product": [ 25858 ], + "mode": "StandardEject", + "msg": [ ] + }, + ":uMa=CELOT": { + "t_vendor": 8479, + "t_product": [ 26625, 26626 ], + "mode": "StandardEject", + "msg": [ ] + }, + ":uMa=Co.,Ltd": { + "t_vendor": 7433, + "t_product": [ 17158 ], + "mode": "StandardEject", + "msg": [ ] + }, + ":uMa=DGT": { + "t_vendor": 8479, + "t_product": [ 26626 ], + "mode": "StandardEject", + "msg": [ ] + }, + ":uMa=SAMSUNG": { + "t_vendor": 1256, + "t_product": [ 26113 ], + "msg": [ 7 ] + }, + ":uMa=SSE": { + "t_vendor": 1478, + "t_product": [ 24576 ], + "mode": "StandardEject", + "msg": [ ] + }, + ":uMa=StrongRising": { + "t_vendor": 650, + "t_product": [ 4102 ], + "mode": "StandardEject", + "msg": [ ] + }, + ":uMa=Vertex": { + "t_vendor": 8167, + "t_product": [ 256 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "05c6:2000": { + "*": { + "t_vendor": 1478, + "t_product": [ 21, 22, 24, 52759 ], + "msg": [ 10 ], + "response": true, + "check": true + } + }, + "05c6:2001": { + "*": { + "t_vendor": 7694, + "t_product": [ 52758, 52759, 52990 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "05c6:6503": { + "*": { + "t_vendor": 5845, + "t_product": [ 25858 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "05c6:9024": { + "*": { + "t_vendor": 1478, + "t_product": [ 36901 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "05c6:98ff": { + "*": { + "t_vendor": 1478, + "t_product": [ 24577 ], + "mode": "Sierra", + "msg": [ ] + } + }, + "05c6:f000": { + "*": { + "t_vendor": 1478, + "t_product": [ 22, 24576, 36864 ], + "mode": "StandardEject", + "msg": [ 11 ] + } + }, + "05c7:1000": { + "*": { + "t_vendor": 1479, + "t_product": [ 24576 ], + "msg": [ 12 ] + } + }, + "0685:2000": { + "*": { + "t_vendor": 7326, + "t_product": [ 38403 ], + "msg": [ 10 ], + "response": true + } + }, + "072f:100d": { + "*": { + "t_vendor": 1839, + "t_product": [ 37068 ], + "msg_endpoint": 2, + "msg": [ 13 ] + } + }, + "07d1:a800": { + "*": { + "t_vendor": 2001, + "t_product": [ 15873, 15874, 32268 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "07d1:a804": { + "*": { + "t_vendor": 2001, + "t_product": [ 32273 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "07d1:f000": { + "*": { + "t_vendor": 2001, + "t_product": [ 32263 ], + "msg": [ 14 ] + } + }, + "0846:0fff": { + "*": { + "t_vendor": 2118, + "t_product": [ 26835 ], + "mode": "Sierra", + "msg": [ ] + } + }, + "0922:1001": { + "*": { + "t_vendor": 2338, + "t_product": [ 4098 ], + "msg_endpoint": 1, + "msg": [ 15 ], + "response_endpoint": 1 + } + }, + "0922:1003": { + "*": { + "t_vendor": 2338, + "t_product": [ 4100 ], + "msg_endpoint": 1, + "msg": [ 15 ], + "response_endpoint": 1 + } + }, + "0922:1007": { + "*": { + "t_vendor": 2338, + "t_product": [ 4104 ], + "msg_endpoint": 1, + "msg": [ 15 ], + "response_endpoint": 1 + } + }, + "0930:0d46": { + "*": { + "t_vendor": 2352, + "t_product": [ 3397 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0ace:2011": { + "*": { + "mode": "StandardEject", + "msg": [ ] + } + }, + "0ace:20ff": { + "*": { + "mode": "StandardEject", + "msg": [ ] + } + }, + "0af0:4007": { + "*": { + "t_vendor": 2800, + "t_product": [ 16389 ], + "mode": "Sierra", + "msg": [ ] + } + }, + "0b3c:c700": { + "*": { + "t_vendor": 2876, + "t_product": [ 49152, 49153, 49154 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0b3c:f000": { + "*": { + "t_vendor": 2876, + "t_product": [ 49155, 49156 ], + "msg": [ 16 ], + "response": true + } + }, + "0b3c:f00c": { + "*": { + "t_vendor": 2876, + "t_product": [ 49162 ], + "msg": [ 17 ] + } + }, + "0b3c:f017": { + "*": { + "t_vendor": 2876, + "t_product": [ 49163 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0bdb:190d": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "0bdb:1910": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "0cf3:20ff": { + "*": { + "t_vendor": 3315, + "t_product": [ 28688 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0d46:45a1": { + "*": { + "t_vendor": 3398, + "t_product": [ 17833 ], + "mode": "Kobil", + "msg": [ ] + } + }, + "0d46:45a5": { + "*": { + "t_vendor": 3398, + "t_product": [ 17837 ], + "mode": "Kobil", + "msg": [ ] + } + }, + "0df7:0800": { + "*": { + "t_class": 255, + "mode": "MobileAction", + "msg": [ ] + } + }, + "0e8d:0002": { + ":uPr=MT": { + "t_vendor": 3725, + "t_product": [ 161, 162, 165 ], + "msg": [ 18 ] + }, + ":uPr=Product": { + "t_vendor": 3725, + "t_product": [ 161, 162, 165 ], + "msg": [ 18 ] + } + }, + "0e8d:7109": { + "*": { + "t_vendor": 3725, + "t_product": [ 28949, 28952 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "0fce:d0cf": { + "*": { + "msg": [ ], + "config": 3 + } + }, + "0fce:d0df": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "0fce:d0e1": { + "*": { + "t_class": 2, + "mode": "Sony", + "msg": [ ], + "config": 2 + } + }, + "0fce:d103": { + "*": { + "t_class": 2, + "mode": "Sony", + "msg": [ ], + "config": 2 + } + }, + "0fd1:1000": { + "*": { + "msg": [ ], + "config": 3 + } + }, + "1004:1000": { + "*": { + "t_class": 255, + "msg": [ 19 ] + } + }, + "1004:607f": { + "*": { + "t_vendor": 4100, + "t_product": [ 24576, 24852 ], + "msg": [ 20 ], + "response": true + } + }, + "1004:610c": { + "*": { + "t_vendor": 4100, + "t_product": [ 24841 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1004:613a": { + "*": { + "t_vendor": 4100, + "t_product": [ 24868 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1004:613f": { + "*": { + "t_vendor": 4100, + "t_product": [ 24897 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1004:614e": { + "*": { + "t_vendor": 4100, + "t_product": [ 24885 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1004:6156": { + "*": { + "t_vendor": 4100, + "t_product": [ 24919 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1004:6190": { + "*": { + "t_vendor": 4100, + "t_product": [ 24963, 24999 ], + "mode": "StandardEject", + "msg": [ ], + "wait": 10 + } + }, + "1004:61dd": { + "*": { + "t_vendor": 4100, + "t_product": [ 24975 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1004:61e7": { + "*": { + "t_vendor": 4100, + "t_product": [ 25062 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1004:61eb": { + "*": { + "t_vendor": 4100, + "t_product": [ 25066 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1004:6327": { + "*": { + "t_vendor": 4100, + "t_product": [ 25382 ], + "msg": [ 21 ] + } + }, + "106c:3b03": { + "*": { + "t_vendor": 4204, + "t_product": [ 14101 ], + "msg": [ 22 ] + } + }, + "106c:3b05": { + "*": { + "t_vendor": 4204, + "t_product": [ 14102 ], + "msg": [ 23 ] + } + }, + "106c:3b06": { + "*": { + "t_vendor": 4204, + "t_product": [ 14103 ], + "msg": [ 24 ] + } + }, + "106c:3b11": { + "*": { + "t_vendor": 4204, + "t_product": [ 14104 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "106c:3b14": { + "*": { + "t_vendor": 4204, + "t_product": [ 14113 ], + "msg": [ 22 ] + } + }, + "1076:7f40": { + "*": { + "t_vendor": 4214, + "t_product": [ 32512 ], + "mode": "GCT", + "msg": [ ] + } + }, + "109b:f009": { + "*": { + "t_vendor": 4251, + "t_product": [ 37140 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1199:0fff": { + "*": { + "t_vendor": 4505, + "t_product": [ 23, 24, 25, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 274, 288, 536, 544, 548, 769, 26626, 26627, 26628, 26629, 26632, 26633, 26642, 26643, 26645, 26646, 26656, 26657, 26658, 26674, 26675, 26676, 26677, 26680, 26681, 26682, 26683, 26684, 26685, 26686, 26704, 26705, 26706, 26707, 26709, 26710, 26713, 26714, 26752, 26768, 26769, 26770, 26771, 26786, 26787, 26794, 36881, 36882, 36945 ], + "mode": "Sierra", + "msg": [ ] + } + }, + "1199:9011": { + "*": { + "msg": [ ], + "config": 1 + } + }, + "1199:9013": { + "*": { + "msg": [ ], + "config": 1 + } + }, + "1199:9017": { + "*": { + "msg": [ ], + "config": 1 + } + }, + "1199:901b": { + "*": { + "msg": [ ], + "config": 1 + } + }, + "1199:901c": { + "*": { + "msg": [ ], + "config": 1 + } + }, + "1199:901f": { + "*": { + "msg": [ ], + "config": 1 + } + }, + "1199:9041": { + "*": { + "msg": [ ], + "config": 1 + } + }, + "1199:9051": { + "*": { + "msg": [ ], + "config": 1 + } + }, + "1199:9053": { + "*": { + "msg": [ ], + "config": 1 + } + }, + "1199:9063": { + "*": { + "msg": [ ], + "config": 1 + } + }, + "1266:1000": { + "*": { + "t_vendor": 4710, + "t_product": [ 4098, 4099, 4100, 4101, 4102, 4103, 4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4113, 4114 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "12d1:1001": { + "*": { + "t_class": 255, + "mode": "Huawei", + "msg": [ ] + } + }, + "12d1:1003": { + "*": { + "t_class": 255, + "mode": "Huawei", + "msg": [ ] + } + }, + "12d1:1009": { + "*": { + "t_class": 255, + "mode": "Huawei", + "msg": [ ] + } + }, + "12d1:1010": { + "*": { + "t_class": 255, + "mode": "Huawei", + "msg": [ ] + } + }, + "12d1:101e": { + "*": { + "t_class": 255, + "msg": [ 25 ] + } + }, + "12d1:1030": { + "*": { + "t_vendor": 4817, + "t_product": [ 4148 ], + "msg": [ 26 ] + } + }, + "12d1:1031": { + "*": { + "t_vendor": 4817, + "t_product": [ 4149 ], + "msg": [ 26 ] + } + }, + "12d1:1413": { + "*": { + "t_class": 255, + "mode": "Huawei", + "msg": [ ] + } + }, + "12d1:1414": { + "*": { + "t_class": 255, + "mode": "Huawei", + "msg": [ ] + } + }, + "12d1:1446": { + "*": { + "t_vendor": 4817, + "t_product": [ 4097, 5124, 5126, 5131, 5132, 5138, 5143, 5147, 5161, 5170, 5171, 5174, 5292, 5382, 5388, 5393 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1449": { + "*": { + "t_vendor": 4817, + "t_product": [ 5188 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:14ad": { + "*": { + "t_vendor": 4817, + "t_product": [ 5294 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:14b5": { + "*": { + "t_vendor": 4817, + "t_product": [ 5288, 5290 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:14b7": { + "*": { + "t_vendor": 4817, + "t_product": [ 5324 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:14ba": { + "*": { + "t_vendor": 4817, + "t_product": [ 5330 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:14c1": { + "*": { + "t_vendor": 4817, + "t_product": [ 5318 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:14c3": { + "*": { + "t_vendor": 4817, + "t_product": [ 5320 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:14c4": { + "*": { + "t_vendor": 4817, + "t_product": [ 5322 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:14c5": { + "*": { + "t_vendor": 4817, + "t_product": [ 5323 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:14d1": { + "*": { + "t_vendor": 4817, + "t_product": [ 5321 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:14fe": { + "*": { + "t_vendor": 4817, + "t_product": [ 5382, 5391, 5405, 7198 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1505": { + "*": { + "t_vendor": 4817, + "t_product": [ 5131, 5132, 5382, 5391, 5386 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:151a": { + "*": { + "t_vendor": 4817, + "t_product": [ 5403, 5405, 5406 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1520": { + "*": { + "t_vendor": 4817, + "t_product": [ 5221 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1521": { + "*": { + "t_vendor": 4817, + "t_product": [ 5220 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1523": { + "*": { + "t_vendor": 4817, + "t_product": [ 5265 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1526": { + "*": { + "t_vendor": 4817, + "t_product": [ 5327 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1527": { + "*": { + "t_vendor": 4817, + "t_product": [ 5524 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1553": { + "*": { + "t_vendor": 4817, + "t_product": [ 4097 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1557": { + "*": { + "t_vendor": 4817, + "t_product": [ 5285 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:155a": { + "*": { + "t_vendor": 4817, + "t_product": [ 5325 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:155b": { + "*": { + "t_vendor": 4817, + "t_product": [ 5382 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:156a": { + "*": { + "t_vendor": 4817, + "t_product": [ 5483, 5484 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1570": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "12d1:1571": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "12d1:1572": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "12d1:1573": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "12d1:157c": { + "*": { + "t_vendor": 4817, + "t_product": [ 5382 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:157d": { + "*": { + "t_vendor": 4817, + "t_product": [ 5339, 5340 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1580": { + "*": { + "t_vendor": 4817, + "t_product": [ 5509 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1581": { + "*": { + "t_vendor": 4817, + "t_product": [ 5511 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1582": { + "*": { + "t_vendor": 4817, + "t_product": [ 5512 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1583": { + "*": { + "t_vendor": 4817, + "t_product": [ 5513 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1597": { + "*": { + "t_vendor": 4817, + "t_product": [ 5528 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:15bb": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "12d1:15c0": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "12d1:15c1": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "12d1:15ca": { + "*": { + "t_vendor": 4817, + "t_product": [ 5382 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:15cd": { + "*": { + "t_vendor": 4817, + "t_product": [ 5382 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:15ce": { + "*": { + "t_vendor": 4817, + "t_product": [ 5553, 5555 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:15cf": { + "*": { + "t_vendor": 4817, + "t_product": [ 5382 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:15d0": { + "*": { + "t_vendor": 4817, + "t_product": [ 5585 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:15d2": { + "*": { + "t_vendor": 4817, + "t_product": [ 5587 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:15e7": { + "*": { + "t_vendor": 4817, + "t_product": [ 5382 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:15ec": { + "*": { + "t_vendor": 4817, + "t_product": [ 7206 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:15f0": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "12d1:1805": { + "*": { + "t_class": 255, + "msg": [ 25 ] + } + }, + "12d1:1c0b": { + "*": { + "t_vendor": 4817, + "t_product": [ 7173, 7174, 7175, 7176, 7184 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1c1b": { + "*": { + "t_vendor": 4817, + "t_product": [ 5382 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1c24": { + "*": { + "t_vendor": 4817, + "t_product": [ 7186, 7203 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1c25": { + "*": { + "msg": [ ], + "config": 0 + } + }, + "12d1:1d50": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "12d1:1da1": { + "*": { + "t_vendor": 4817, + "t_product": [ 7433 ], + "mode": "Huawei", + "msg": [ ] + } + }, + "12d1:1f01": { + "*": { + "t_vendor": 4817, + "t_product": [ 5339, 5340 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f02": { + "*": { + "t_vendor": 4817, + "t_product": [ 5340 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f03": { + "*": { + "t_vendor": 4817, + "t_product": [ 5339 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f04": { + "*": { + "t_vendor": 4817, + "t_product": [ 5564 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f05": { + "*": { + "t_vendor": 4817, + "t_product": [ 5565 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f06": { + "*": { + "t_vendor": 4817, + "t_product": [ 5575 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f07": { + "*": { + "t_vendor": 4817, + "t_product": [ 5567 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f09": { + "*": { + "t_vendor": 4817, + "t_product": [ 7248 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f11": { + "*": { + "t_vendor": 4817, + "t_product": [ 5308 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f15": { + "*": { + "t_vendor": 4817, + "t_product": [ 5120, 5367 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f16": { + "*": { + "mode": "MBIM", + "msg": [ ] + } + }, + "12d1:1f17": { + "*": { + "t_vendor": 4817, + "t_product": [ 5494 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f18": { + "*": { + "t_vendor": 4817, + "t_product": [ 5495 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f19": { + "*": { + "t_vendor": 4817, + "t_product": [ 5370, 5493, 5496 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f1b": { + "*": { + "t_vendor": 4817, + "t_product": [ 5497 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f1c": { + "*": { + "t_vendor": 4817, + "t_product": [ 5498, 5520 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f1d": { + "*": { + "t_vendor": 4817, + "t_product": [ 5499, 5521 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:1f1e": { + "*": { + "t_vendor": 4817, + "t_product": [ 5503, 5522 ], + "mode": "HuaweiNew", + "msg": [ ] + } + }, + "12d1:380b": { + "*": { + "t_class": 2, + "mode": "StandardEject", + "msg": [ ] + } + }, + "1307:1169": { + "*": { + "t_vendor": 5041, + "t_product": [ 49 ], + "mode": "Cisco", + "msg": [ ] + } + }, + "1410:5010": { + "*": { + "t_vendor": 5136, + "t_product": [ 16640, 17408, 28720 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1410:5020": { + "*": { + "t_vendor": 5136, + "t_product": [ 24576, 28673 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1410:5023": { + "*": { + "t_vendor": 5136, + "t_product": [ 28720 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1410:5030": { + "*": { + "t_vendor": 5136, + "t_product": [ 24576 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1410:5031": { + "*": { + "t_vendor": 5136, + "t_product": [ 24578 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1410:5041": { + "*": { + "t_vendor": 5136, + "t_product": [ 28673, 28675 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1410:5055": { + "*": { + "t_vendor": 5136, + "t_product": [ 24626 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1410:5059": { + "*": { + "t_vendor": 5136, + "t_product": [ 28721, 28738 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1410:7001": { + "*": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + } + }, + "1410:9020": { + "*": { + "msg": [ ], + "config": 4 + } + }, + "148e:a000": { + "*": { + "t_class": 2, + "mode": "Sequans", + "msg": [ ] + } + }, + "148f:2578": { + "*": { + "t_vendor": 5263, + "t_product": [ 36897 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "148f:2878": { + "*": { + "t_vendor": 5263, + "t_product": [ 30209 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "15eb:7153": { + "*": { + "t_vendor": 5611, + "t_product": [ 29010 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1614:0800": { + "*": { + "t_class": 255, + "msg": [ 27 ] + } + }, + "1614:0802": { + "*": { + "t_class": 255, + "msg": [ 27 ] + } + }, + "16d5:f000": { + "*": { + "t_vendor": 5845, + "t_product": [ 26115 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "16d8:6281": { + "*": { + "t_class": 255, + "msg": [ 28 ] + } + }, + "16d8:6803": { + "*": { + "t_class": 2, + "msg": [ 29 ] + } + }, + "16d8:6804": { + "*": { + "t_class": 255, + "msg": [ 28 ] + } + }, + "16d8:700a": { + "*": { + "t_class": 255, + "msg": [ 30 ] + } + }, + "16d8:700b": { + "*": { + "t_class": 255, + "msg": [ 30 ] + } + }, + "16d8:f000": { + "*": { + "t_vendor": 5848, + "t_product": [ 24582 ], + "msg": [ 31 ] + } + }, + "1726:1900": { + "*": { + "t_vendor": 5926, + "t_product": [ 4096 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1726:f00e": { + "*": { + "t_vendor": 5926, + "t_product": [ 40960 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1782:0003": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "1782:0023": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "198a:0003": { + "*": { + "t_vendor": 6538, + "t_product": [ 2 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "198f:bccd": { + "*": { + "t_vendor": 6543, + "t_product": [ 544 ], + "msg": [ 4 ] + } + }, + "19d2:0003": { + "*": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0026": { + "*": { + "t_vendor": 6610, + "t_product": [ 115, 148, 338 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0033": { + "*": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0040": { + "*": { + "t_vendor": 6610, + "t_product": [ 34 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0053": { + "*": { + "t_vendor": 6610, + "t_product": [ 49 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0083": { + ":uPr=WCDMA": { + "t_vendor": 6610, + "t_product": [ 292 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0090": { + "*": { + "t_vendor": 6610, + "t_product": [ 52 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0101": { + "*": { + "t_vendor": 6610, + "t_product": [ 260 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0103": { + "*": { + "t_vendor": 6610, + "t_product": [ 49 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0110": { + "*": { + "t_vendor": 6610, + "t_product": [ 289 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0115": { + "*": { + "t_vendor": 6610, + "t_product": [ 278 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0120": { + "*": { + "t_vendor": 6610, + "t_product": [ 121 ], + "detach_storage": false, + "mode": "StandardEject", + "msg": [ ], + "response": false, + "interface": 0 + } + }, + "19d2:0146": { + "*": { + "t_vendor": 6610, + "t_product": [ 322, 323 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0149": { + "*": { + "t_vendor": 6610, + "t_product": [ 292 ], + "mode": "StandardEject", + "msg": [ 32 ] + } + }, + "19d2:0150": { + "*": { + "t_vendor": 6610, + "t_product": [ 292 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0154": { + "*": { + "t_vendor": 6610, + "t_product": [ 23, 279, 8195 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0166": { + "*": { + "t_vendor": 6610, + "t_product": [ 359 ], + "msg": [ 33 ] + } + }, + "19d2:0169": { + "*": { + "t_vendor": 6610, + "t_product": [ 368 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0198": { + "*": { + "t_vendor": 6610, + "t_product": [ 409 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0266": { + "*": { + "t_vendor": 6610, + "t_product": [ 613 ], + "mode": "StandardEject", + "msg": [ 34 ] + } + }, + "19d2:0304": { + "*": { + "t_vendor": 6610, + "t_product": [ 841 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0318": { + "*": { + "t_vendor": 6610, + "t_product": [ 791, 816 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0325": { + "*": { + "t_vendor": 6610, + "t_product": [ 806 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:0388": { + "*": { + "t_vendor": 6610, + "t_product": [ 1095 ], + "msg": [ 33 ] + } + }, + "19d2:0413": { + "*": { + "t_vendor": 6610, + "t_product": [ 1042 ], + "msg": [ 34 ] + } + }, + "19d2:1001": { + "*": { + "t_vendor": 6610, + "t_product": [ 4098, 4099 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1007": { + "*": { + "t_vendor": 6610, + "t_product": [ 4104 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1009": { + "*": { + "t_vendor": 6610, + "t_product": [ 4112 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1013": { + "*": { + "t_vendor": 6610, + "t_product": [ 4117 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1017": { + "*": { + "t_vendor": 6610, + "t_product": [ 4120 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1019": { + "*": { + "t_vendor": 6610, + "t_product": [ 4129 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1020": { + "*": { + "t_vendor": 6610, + "t_product": [ 4129 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1022": { + "*": { + "t_vendor": 6610, + "t_product": [ 4131, 4132 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1026": { + "*": { + "t_vendor": 6610, + "t_product": [ 4135, 4136, 4137 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1030": { + "*": { + "t_vendor": 6610, + "t_product": [ 4145, 4146 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1034": { + "*": { + "t_vendor": 6610, + "t_product": [ 4149, 4150, 4151 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1038": { + "*": { + "t_vendor": 6610, + "t_product": [ 4153, 4160 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1042": { + "*": { + "t_vendor": 6610, + "t_product": [ 4163 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1046": { + "*": { + "t_vendor": 6610, + "t_product": [ 4167 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1171": { + "*": { + "t_vendor": 6610, + "t_product": [ 4467 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1175": { + "*": { + "t_vendor": 6610, + "t_product": [ 4471 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1179": { + "*": { + "t_vendor": 6610, + "t_product": [ 4481 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1201": { + "*": { + "t_vendor": 6610, + "t_product": [ 4611 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1207": { + "*": { + "t_vendor": 6610, + "t_product": [ 4616 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1210": { + "*": { + "t_vendor": 6610, + "t_product": [ 4625 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1216": { + "*": { + "t_vendor": 6610, + "t_product": [ 4631 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1219": { + "*": { + "t_vendor": 6610, + "t_product": [ 4640, 4642 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1224": { + "*": { + "t_vendor": 6610, + "t_product": [ 130 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1225": { + "*": { + "t_vendor": 6610, + "t_product": [ 5125 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1227": { + "*": { + "t_vendor": 6610, + "t_product": [ 4690 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1232": { + "*": { + "t_vendor": 6610, + "t_product": [ 4712, 8195 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1233": { + "*": { + "t_vendor": 6610, + "t_product": [ 4720 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1237": { + "*": { + "t_vendor": 6610, + "t_product": [ 23 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1238": { + "*": { + "t_vendor": 6610, + "t_product": [ 23 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1420": { + "*": { + "t_vendor": 6610, + "t_product": [ 5125 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1511": { + "*": { + "t_vendor": 6610, + "t_product": [ 5394 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1514": { + "*": { + "t_vendor": 6610, + "t_product": [ 5397 ], + "msg": [ 35 ] + } + }, + "19d2:1517": { + "*": { + "t_vendor": 6610, + "t_product": [ 5401 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1520": { + "*": { + "t_vendor": 6610, + "t_product": [ 322 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1523": { + "*": { + "t_vendor": 6610, + "t_product": [ 5413 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1528": { + "*": { + "t_vendor": 6610, + "t_product": [ 5415 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1536": { + "*": { + "t_vendor": 6610, + "t_product": [ 5431, 5432 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1542": { + "*": { + "t_vendor": 6610, + "t_product": [ 5444 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1580": { + "*": { + "t_vendor": 6610, + "t_product": [ 5506 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:1588": { + "*": { + "t_vendor": 6610, + "t_product": [ 5513, 5521, 5522 ], + "mode": "StandardEject", + "msg": [ 32 ] + } + }, + "19d2:1595": { + "*": { + "t_vendor": 6610, + "t_product": [ 5428, 5522, 5526, 5632 ], + "mode": "StandardEject", + "msg": [ 32 ] + } + }, + "19d2:2000": { + "*": { + "t_vendor": 6610, + "t_product": [ 1, 2, 21, 22, 23, 25, 36, 49, 51, 55, 66, 82, 85, 97, 99, 100, 102, 145, 264, 279, 296, 337, 343, 375, 5122, 8194, 8195 ], + "mode": "StandardEject", + "msg": [ 32 ] + } + }, + "19d2:2004": { + "*": { + "t_vendor": 6610, + "t_product": [ 5122 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:bccd": { + "*": { + "t_vendor": 6610, + "t_product": [ 370 ], + "msg": [ 36 ] + } + }, + "19d2:ffde": { + "*": { + "t_vendor": 6610, + "t_product": [ 65501 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "19d2:ffe6": { + "*": { + "t_vendor": 6610, + "t_product": [ 65509 ], + "msg": [ 37 ] + } + }, + "19d2:fff5": { + "*": { + "t_vendor": 6610, + "t_product": [ 65508, 65513, 65521, 65534, 65535 ], + "msg": [ 38 ] + } + }, + "19d2:fff6": { + "*": { + "t_vendor": 6610, + "t_product": [ 65521 ], + "msg": [ 38 ] + } + }, + "1a8d:1000": { + "*": { + "t_vendor": 6797, + "t_product": [ 4098, 4103, 4105, 4109, 8198 ], + "mode": "StandardEject", + "msg": [ ], + "release_delay": 4000, + "response": true + } + }, + "1a8d:2000": { + "*": { + "t_vendor": 6797, + "t_product": [ 8198 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1ab7:5700": { + "*": { + "t_vendor": 6839, + "t_product": [ 8192, 22321 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1b7d:0700": { + "*": { + "t_vendor": 7037, + "t_product": [ 1 ], + "msg": [ 39 ] + } + }, + "1bbb:000f": { + "*": { + "t_vendor": 7099, + "t_product": [ 15 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1bbb:00ca": { + "*": { + "t_class": 255, + "msg": [ 17 ] + } + }, + "1bbb:011f": { + "*": { + "t_vendor": 7099, + "t_product": [ 262 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1bbb:022c": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "1bbb:025e": { + "*": { + "t_vendor": 7099, + "t_product": [ 405 ], + "msg": [ 17 ] + } + }, + "1bbb:f000": { + "*": { + "t_vendor": 7099, + "t_product": [ 0, 23, 183, 286, 401, 405 ], + "msg": [ 17 ] + } + }, + "1bbb:f017": { + "*": { + "t_vendor": 7099, + "t_product": [ 23, 286, 515 ], + "msg": [ 17 ] + } + }, + "1bbb:f052": { + "*": { + "t_vendor": 7099, + "t_product": [ 82 ], + "msg": [ 17 ] + } + }, + "1c9e:1001": { + "*": { + "t_vendor": 7326, + "t_product": [ 24672, 24673 ], + "msg": [ 40 ] + } + }, + "1c9e:6000": { + "*": { + "t_class": 255, + "msg": [ 27 ] + } + }, + "1c9e:6061": { + ":uPr=Storage": { + "t_class": 255, + "msg": [ 40 ] + } + }, + "1c9e:9101": { + "*": { + "t_vendor": 7326, + "t_product": [ 37124 ], + "msg": [ 40 ] + } + }, + "1c9e:9200": { + "*": { + "t_vendor": 7326, + "t_product": [ 37378 ], + "msg": [ 40 ] + } + }, + "1c9e:9401": { + "*": { + "t_vendor": 7326, + "t_product": [ 37892 ], + "msg": [ 40 ] + } + }, + "1c9e:9800": { + "*": { + "t_class": 255, + "msg": [ 17 ] + } + }, + "1c9e:98ff": { + "*": { + "t_vendor": 7326, + "t_product": [ 26625, 38913, 38915 ], + "msg": [ 41 ] + } + }, + "1c9e:9bfe": { + "*": { + "t_vendor": 7326, + "t_product": [ 39681 ], + "msg": [ 40 ] + } + }, + "1c9e:9d00": { + "*": { + "t_class": 255, + "msg": [ 40 ] + } + }, + "1c9e:9e00": { + "*": { + "t_class": 255, + "msg": [ 40 ] + } + }, + "1c9e:9e08": { + "*": { + "t_vendor": 7326, + "t_product": [ 40472 ], + "mode": "Sierra", + "msg": [ ] + } + }, + "1c9e:f000": { + "*": { + "t_vendor": 7326, + "t_product": [ 36864, 38403, 38405, 38407, 39168 ], + "msg": [ 42 ], + "wait": 1 + }, + ":uMa=USB_Modem": { + "t_vendor": 7326, + "t_product": [ 36864, 38403, 38405, 38407, 39168, 39424 ], + "msg": [ 17 ], + "wait": 1 + } + }, + "1c9e:f010": { + "*": { + "t_vendor": 7326, + "t_product": [ 61697 ], + "msg": [ 40 ] + } + }, + "1d09:1000": { + "*": { + "t_vendor": 7433, + "t_product": [ 4112 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1d09:1021": { + "*": { + "t_vendor": 7433, + "t_product": [ 4112 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1d09:1025": { + "*": { + "t_vendor": 7433, + "t_product": [ 4134 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "1da5:f000": { + "*": { + "t_vendor": 7589, + "t_product": [ 17682 ], + "mode": "Qisda", + "msg": [ ] + } + }, + "1dbc:0669": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "1dd6:1000": { + "*": { + "t_vendor": 7638, + "t_product": [ 4098 ], + "msg": [ 43 ], + "response": true + } + }, + "1de1:1101": { + "*": { + "t_vendor": 8679, + "t_product": [ 14 ], + "msg": [ 44 ] + } + }, + "1e0e:f000": { + "*": { + "t_vendor": 7694, + "t_product": [ 36864, 37120, 37376 ], + "msg": [ 14 ], + "response": true + } + }, + "1e89:f000": { + "*": { + "t_vendor": 7817, + "t_product": [ 6688 ], + "msg": [ 45 ] + } + }, + "1edf:6003": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "1ee8:0003": { + "*": { + "t_vendor": 7912, + "t_product": [ 4 ], + "msg": [ 46 ], + "response": true + } + }, + "1ee8:0007": { + "*": { + "t_vendor": 7912, + "t_product": [ 11 ], + "msg": [ 46 ] + } + }, + "1ee8:0009": { + "*": { + "t_vendor": 7912, + "t_product": [ 11 ], + "msg": [ 46 ], + "response": true + } + }, + "1ee8:0013": { + "*": { + "t_vendor": 7912, + "t_product": [ 17, 18, 20 ], + "msg": [ 46 ], + "response": true + } + }, + "1ee8:0018": { + "*": { + "t_vendor": 7912, + "t_product": [ 23 ], + "msg": [ 46 ], + "response": true + } + }, + "1ee8:0040": { + "*": { + "t_vendor": 7912, + "t_product": [ 62, 63 ], + "msg": [ 46 ], + "response": true + } + }, + "1ee8:0045": { + "*": { + "t_vendor": 7912, + "t_product": [ 68 ], + "msg": [ 46 ], + "response": true + } + }, + "1ee8:0048": { + "*": { + "t_vendor": 7912, + "t_product": [ 73 ], + "msg": [ 46 ] + } + }, + "1ee8:004a": { + "*": { + "t_vendor": 7912, + "t_product": [ 73 ], + "msg": [ 46 ] + } + }, + "1ee8:004f": { + "*": { + "t_vendor": 7912, + "t_product": [ 78 ], + "msg": [ 46 ], + "response": true + } + }, + "1ee8:0054": { + "*": { + "t_vendor": 7912, + "t_product": [ 83 ], + "msg": [ 46 ], + "response": true + } + }, + "1ee8:0060": { + "*": { + "t_vendor": 7912, + "t_product": [ 95 ], + "msg": [ 47 ] + } + }, + "1ee8:0063": { + "*": { + "t_vendor": 7912, + "t_product": [ 100, 101 ], + "msg": [ 47 ] + } + }, + "1ee8:0068": { + "*": { + "t_vendor": 7912, + "t_product": [ 105 ], + "msg": [ 47 ] + } + }, + "1f28:0021": { + "*": { + "t_vendor": 7976, + "t_product": [ 32 ], + "msg": [ 48 ] + } + }, + "1fac:0032": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "1fac:0130": { + "*": { + "t_vendor": 8108, + "t_product": [ 305 ], + "msg": [ 48 ] + } + }, + "1fac:0150": { + "*": { + "t_vendor": 8108, + "t_product": [ 337 ], + "msg": [ 48 ] + } + }, + "1fac:0151": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "2001:00a6": { + "*": { + "t_vendor": 8193, + "t_product": [ 32002 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:00a7": { + "*": { + "t_vendor": 8193, + "t_product": [ 32014 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:7600": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "2001:98ff": { + "*": { + "t_vendor": 8193, + "t_product": [ 32278 ], + "msg": [ 49 ], + "response": true + } + }, + "2001:a401": { + "*": { + "t_vendor": 8193, + "t_product": [ 32281 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a403": { + "*": { + "t_vendor": 8193, + "t_product": [ 32011, 32012 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a405": { + "*": { + "t_vendor": 8193, + "t_product": [ 32013 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a406": { + "*": { + "t_vendor": 8193, + "t_product": [ 32281 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a407": { + "*": { + "t_vendor": 8193, + "t_product": [ 32014 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a40a": { + "*": { + "t_vendor": 8193, + "t_product": [ 32016 ], + "msg": [ 50 ] + } + }, + "2001:a40d": { + "*": { + "t_vendor": 8193, + "t_product": [ 32312 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a706": { + "*": { + "t_vendor": 8193, + "t_product": [ 32001 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a707": { + "*": { + "t_vendor": 8193, + "t_product": [ 32002 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a708": { + "*": { + "t_vendor": 8193, + "t_product": [ 32003 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a805": { + "*": { + "t_vendor": 8193, + "t_product": [ 32274 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a809": { + "*": { + "t_vendor": 8193, + "t_product": [ 30976 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:a80b": { + "*": { + "t_vendor": 8193, + "t_product": [ 32000 ], + "msg": [ 50 ], + "response": true + } + }, + "2001:ab00": { + "*": { + "t_vendor": 8193, + "t_product": [ 32309 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2001:ac01": { + "*": { + "t_vendor": 8193, + "t_product": [ 32317 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2015:0001": { + "*": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + } + }, + "201e:1023": { + "*": { + "t_vendor": 8222, + "t_product": [ 4130 ], + "msg": [ 51, 52 ], + "response": true + } + }, + "201e:2009": { + "*": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + } + }, + "2020:0002": { + "*": { + "t_vendor": 8224, + "t_product": [ 8192, 16384, 16400 ], + "msg": [ 53 ] + } + }, + "2020:f00e": { + "*": { + "t_vendor": 8224, + "t_product": [ 4101, 4104 ], + "mode": "StandardEject", + "msg": [ ], + "wait": 2 + } + }, + "2020:f00f": { + "*": { + "t_vendor": 8224, + "t_product": [ 4101 ], + "mode": "StandardEject", + "msg": [ ], + "wait": 2 + } + }, + "2077:1000": { + "*": { + "t_vendor": 8311, + "t_product": [ 28673, 28688, 28689 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2077:f000": { + "*": { + "t_vendor": 8311, + "t_product": [ 36864, 36962, 40960, 40963 ], + "mode": "StandardEject", + "msg": [ 54 ] + } + }, + "20a6:f00a": { + "*": { + "t_vendor": 8358, + "t_product": [ 4096 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "20a6:f00e": { + "*": { + "t_vendor": 8358, + "t_product": [ 4357 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "20b9:1682": { + "*": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + } + }, + "21f5:1000": { + "*": { + "t_vendor": 8693, + "t_product": [ 8200 ], + "msg": [ 55 ] + } + }, + "21f5:3010": { + "*": { + "t_vendor": 8693, + "t_product": [ 4353 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2262:0001": { + "*": { + "t_vendor": 8802, + "t_product": [ 2 ], + "msg": [ 56 ] + } + }, + "22de:6801": { + "*": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + } + }, + "22de:6802": { + "*": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + } + }, + "22de:6803": { + "*": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + } + }, + "22f4:0021": { + "*": { + "t_class": 255, + "mode": "StandardEject", + "msg": [ ] + } + }, + "230d:0001": { + "*": { + "msg": [ ], + "config": 3 + } + }, + "230d:0003": { + "*": { + "msg": [ ], + "config": 3 + } + }, + "230d:0007": { + "*": { + "msg": [ ], + "config": 3 + } + }, + "230d:000b": { + "*": { + "msg": [ ], + "config": 3 + } + }, + "230d:000c": { + "*": { + "msg": [ ], + "config": 3 + } + }, + "230d:000d": { + "*": { + "msg": [ ], + "config": 3 + } + }, + "230d:0101": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "230d:0103": { + "*": { + "msg": [ ], + "config": 2 + } + }, + "2357:0200": { + "*": { + "t_vendor": 9047, + "t_product": [ 513 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "2357:f000": { + "*": { + "t_vendor": 9047, + "t_product": [ 36864 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "23a2:1010": { + "*": { + "t_vendor": 9122, + "t_product": [ 4660 ], + "msg": [ 57 ] + } + }, + "257a:a000": { + "*": { + "t_vendor": 9594, + "t_product": [ 5633, 5663, 5679, 9759, 9775, 13855, 13871 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "257a:b000": { + "*": { + "t_vendor": 9594, + "t_product": [ 5633, 5663, 5679, 9759, 9775, 13855, 13871 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "257a:c000": { + "*": { + "t_vendor": 9594, + "t_product": [ 5633, 5663, 5679, 9759, 9775, 13855, 13871 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "257a:d000": { + "*": { + "t_vendor": 9594, + "t_product": [ 5633, 5663, 5679, 9759, 9775, 13855, 13871 ], + "mode": "StandardEject", + "msg": [ ] + } + }, + "6000:1000": { + "*": { + "t_vendor": 1478, + "t_product": [ 24576 ], + "msg": [ 55 ] + } + }, + "8888:6500": { + "*": { + "t_vendor": 5848, + "t_product": [ 25907 ], + "msg": [ 58 ] + } + }, + "ed09:1021": { + "*": { + "t_vendor": 60681, + "t_product": [ 4112 ], + "mode": "StandardEject", + "msg": [ ] + } + } + } +} diff --git a/rooter/ext-rooter-basic/files/lib/netifd/proto/3x.sh b/rooter/ext-rooter-basic/files/lib/netifd/proto/3x.sh new file mode 100644 index 0000000..f8c71fd --- /dev/null +++ b/rooter/ext-rooter-basic/files/lib/netifd/proto/3x.sh @@ -0,0 +1,171 @@ +#!/bin/sh +INCLUDE_ONLY=1 + +. ../netifd-proto.sh +. ./ppp.sh +init_proto "$@" + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + logger -t "Create PPP Connection" "$@" +} + +chcklog() { + OOX=$1 + CLOG=$(uci get modem.modeminfo$CURRMODEM.log) + if [ $CLOG = "1" ]; then + log "$OOX" + fi +} + +proto_3x_init_config() { + no_device=1 + available=1 + ppp_generic_init_config + proto_config_add_string "device" + proto_config_add_string "apn" + proto_config_add_string "service" + proto_config_add_string "pincode" + proto_config_add_string "dialnumber" +} + +proto_3x_setup() { + local interface="$1" + local chat + + if [ ! -f /tmp/bootend.file ]; then + return 0 + fi + + json_get_var device device + json_get_var apn apn + json_get_var service service + json_get_var pincode pincode + + CURRMODEM=$(uci get network.$interface.currmodem) + + uci set modem.modem$CURRMODEM.connected=0 + uci commit modem + jkillall getsignal$CURRMODEM + rm -f $ROOTER_LINK/getsignal$CURRMODEM + jkillall con_monitor$CURRMODEM + rm -f $ROOTER_LINK/con_monitor$CURRMODEM + + + + [ -e "$device" ] || { + proto_set_available "$interface" 0 + return 1 + } + + if [ $service = "umts" ]; then + idV=$(uci get modem.modem$CURRMODEM.idV) + if [ $idV = 12d1 ]; then + $ROOTER/gcom/gcom-locked "$device" "curc.gcom" "$CURRMODEM" + log "Unsolicited Responses Disabled" + fi + chat="/etc/chatscripts/3g.chat" + if [ -n "$pincode" ]; then + OX=$($ROOTER/gcom/gcom-locked "$device" "setpin.gcom" "$CURRMODEM") + ERROR="ERROR" + if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` + then + log "Modem $CURRMODEM Failed to Unlock SIM Pin" + chcklog "$OX" + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Pin Locked" + proto_notify_error "$interface" PIN_FAILED + proto_block_restart "$interface" + return 1 + fi + fi + export SETUSER=$(uci get modem.modeminfo$CURRMODEM.user) + export SETPASS=$(uci get modem.modeminfo$CURRMODEM.pass) + export SETAUTH=$(uci get modem.modeminfo$CURRMODEM.auth) + OX=$($ROOTER/gcom/gcom-locked "$device" "connect-ppp.gcom" "$CURRMODEM") + ERROR="ERROR" + if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` + then + log "Error for Modem $CURRMODEM on Authorization" + chcklog "$OX" + fi + + if [ -z "$dialnumber" ]; then + dialnumber="*99***1#" + fi + else + chat="/etc/chatscripts/evdo.chat" + fi + + connect="${apn:+USE_APN=$apn }DIALNUMBER=$dialnumber /usr/sbin/chat -t5 -v -E -f $chat" + + ppp_generic_setup "$interface" \ + noaccomp \ + nopcomp \ + novj \ + nobsdcomp \ + noauth \ + lock \ + crtscts \ + 115200 "$device" + + sleep 20 + MAN=$(uci get modem.modem$CURRMODEM.manuf) + MOD=$(uci get modem.modem$CURRMODEM.model) + $ROOTER/log/logger "Modem #$CURRMODEM Connected ($MAN $MOD)" + + if [ -e $ROOTER/modem-led.sh ]; then + $ROOTER/modem-led.sh $CURRMODEM 3 + fi + + PROT=$(uci get modem.modem$CURRMODEM.proto) + if [ $service = "umts" ]; then + ln -s $ROOTER/signal/modemsignal.sh $ROOTER_LINK/getsignal$CURRMODEM + $ROOTER_LINK/getsignal$CURRMODEM $CURRMODEM $PROT & + fi + ln -s $ROOTER/connect/reconnect-ppp.sh $ROOTER_LINK/reconnect$CURRMODEM + ln -s $ROOTER/connect/conmon.sh $ROOTER_LINK/con_monitor$CURRMODEM + $ROOTER_LINK/con_monitor$CURRMODEM $CURRMODEM & + uci set modem.modem$CURRMODEM.connected=1 + uci set modem.modem$CURRMODEM.interface="3x-"$interface + uci commit modem + CLB=$(uci get modem.modeminfo$CURRMODEM.lb) + if [ -e /etc/config/mwan3 ]; then + INTER=$(uci get modem.modeminfo$CURRMODEM.inter) + if [ -z $INTER ]; then + INTER=0 + else + if [ $INTER = 0 ]; then + INTER=$CURRMODEM + fi + fi + + if [ -e $ROOTER/timezone.sh ]; then + TZ=$(uci -q get modem.modeminfo$CURRMODEM.tzone) + if [ "$TZ" = "1" ]; then + log "Set TimeZone" + $ROOTER/timezone.sh & + fi + fi + + ENB=$(uci get mwan3.wan$CURRMODEM.enabled) + if [ ! -z $ENB ]; then + if [ $CLB = "1" ]; then + uci set mwan3.wan$INTER.enabled=1 + else + uci set mwan3.wan$INTER.enabled=0 + fi + uci commit mwan3 + /usr/sbin/mwan3 restart + fi + fi + rm -f /tmp/usbwait + return 0 +} + +proto_3x_teardown() { + proto_kill_command "$interface" +} + +add_protocol 3x diff --git a/rooter/ext-rooter-basic/files/lib/upgrade/keep.d/cronfiles b/rooter/ext-rooter-basic/files/lib/upgrade/keep.d/cronfiles new file mode 100644 index 0000000..16cdff4 --- /dev/null +++ b/rooter/ext-rooter-basic/files/lib/upgrade/keep.d/cronfiles @@ -0,0 +1,2 @@ +/etc/cronuser +/etc/cronbase diff --git a/rooter/ext-rooter-basic/files/lib/upgrade/keep.d/rc-local b/rooter/ext-rooter-basic/files/lib/upgrade/keep.d/rc-local new file mode 100644 index 0000000..b68cb69 --- /dev/null +++ b/rooter/ext-rooter-basic/files/lib/upgrade/keep.d/rc-local @@ -0,0 +1,3 @@ +/overlay/upper/etc/rc.local +/etc/rc.local +/usr/lib/scripts diff --git a/rooter/ext-rooter-basic/files/usr/bin/bmask128 b/rooter/ext-rooter-basic/files/usr/bin/bmask128 new file mode 100644 index 0000000..bfd5bde --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/bin/bmask128 @@ -0,0 +1,19 @@ +#!/bin/sh +# +printf "Band 128-bit bandmask\n" +LBAND=1 +BBAND=1 +while [ $LBAND -le 48 ] +do + printf "%-6s%016X%016X\n" "$LBAND" "0" "$BBAND" + LBAND=$(( $LBAND + 1 )) + BBAND=$(( $BBAND * 2 )) +done +LBAND=65 +BBAND=1 +while [ $LBAND -le 85 ] +do + printf "%-6s%016X%016X\n" "$LBAND" "$BBAND" "0" + LBAND=$(( $LBAND + 1 )) + BBAND=$(( $BBAND * 2 )) +done diff --git a/rooter/ext-rooter-basic/files/usr/bin/chan2band.sh b/rooter/ext-rooter-basic/files/usr/bin/chan2band.sh new file mode 100644 index 0000000..5b5bff0 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/bin/chan2band.sh @@ -0,0 +1,317 @@ +#!/bin/sh +CHAN=$1 +CHAN=$(echo "$CHAN" | grep -o "[0-9]*") + +decode_lte() { + if [ $CHAN -lt 600 ]; then + BAND="B1" + elif [ $CHAN -lt 1200 ]; then + BAND="B2" + elif [ $CHAN -lt 1950 ]; then + BAND="B3" + elif [ $CHAN -lt 2400 ]; then + BAND="B4" + elif [ $CHAN -lt 2650 ]; then + BAND="B5" + elif [ $CHAN -lt 2750 ]; then + BAND="B6" + elif [ $CHAN -lt 3450 ]; then + BAND="B7" + elif [ $CHAN -lt 3800 ]; then + BAND="B8" + elif [ $CHAN -lt 4150 ]; then + BAND="B9" + elif [ $CHAN -lt 4750 ]; then + BAND="B10" + elif [ $CHAN -lt 4950 ]; then + BAND="B11" + elif [ $CHAN -lt 5010 ]; then + BAND="-" + elif [ $CHAN -lt 5180 ]; then + BAND="B12" + elif [ $CHAN -lt 5280 ]; then + BAND="B13" + elif [ $CHAN -lt 5380 ]; then + BAND="B14" + elif [ $CHAN -lt 5730 ]; then + BAND="-" + elif [ $CHAN -lt 5850 ]; then + BAND="B17" + elif [ $CHAN -lt 6000 ]; then + BAND="B18" + elif [ $CHAN -lt 6150 ]; then + BAND="B19" + elif [ $CHAN -lt 6450 ]; then + BAND="B20" + elif [ $CHAN -lt 6600 ]; then + BAND="B21" + elif [ $CHAN -lt 7400 ]; then + BAND="B22" + elif [ $CHAN -lt 7500 ]; then + BAND="-" + elif [ $CHAN -lt 7700 ]; then + BAND="B23" + elif [ $CHAN -lt 8040 ]; then + BAND="B24" + elif [ $CHAN -lt 8690 ]; then + BAND="B25" + elif [ $CHAN -lt 9040 ]; then + BAND="B26" + elif [ $CHAN -lt 9210 ]; then + BAND="B27" + elif [ $CHAN -lt 9660 ]; then + BAND="B28" + elif [ $CHAN -lt 9770 ]; then + BAND="B29" + elif [ $CHAN -lt 9870 ]; then + BAND="B30" + elif [ $CHAN -lt 9920 ]; then + BAND="B31" + elif [ $CHAN -lt 10400 ]; then + BAND="B32" + elif [ $CHAN -lt 36000 ]; then + BAND="-" + elif [ $CHAN -lt 36200 ]; then + BAND="B33" + elif [ $CHAN -lt 36350 ]; then + BAND="B34" + elif [ $CHAN -lt 36950 ]; then + BAND="B35" + elif [ $CHAN -lt 37550 ]; then + BAND="B36" + elif [ $CHAN -lt 37750 ]; then + BAND="B37" + elif [ $CHAN -lt 38250 ]; then + BAND="B38" + elif [ $CHAN -lt 38650 ]; then + BAND="B39" + elif [ $CHAN -lt 39650 ]; then + BAND="B40" + elif [ $CHAN -lt 41590 ]; then + BAND="B41" + elif [ $CHAN -lt 43590 ]; then + BAND="B42" + elif [ $CHAN -lt 45590 ]; then + BAND="B43" + elif [ $CHAN -lt 46590 ]; then + BAND="B44" + elif [ $CHAN -lt 46790 ]; then + BAND="B45" + elif [ $CHAN -lt 54540 ]; then + BAND="B46" + elif [ $CHAN -lt 55240 ]; then + BAND="B47" + elif [ $CHAN -lt 56740 ]; then + BAND="B48" + elif [ $CHAN -lt 58240 ]; then + BAND="B49" + elif [ $CHAN -lt 59090 ]; then + BAND="B50" + elif [ $CHAN -lt 59140 ]; then + BAND="B51" + elif [ $CHAN -lt 60140 ]; then + BAND="B52" + elif [ $CHAN -lt 60255 ]; then + BAND="B53" + elif [ $CHAN -lt 65536 ]; then + BAND="-" + elif [ $CHAN -lt 66436 ]; then + BAND="B65" + elif [ $CHAN -lt 67336 ]; then + BAND="B66" + elif [ $CHAN -lt 67536 ]; then + BAND="B67" + elif [ $CHAN -lt 67836 ]; then + BAND="B68" + elif [ $CHAN -lt 68336 ]; then + BAND="B69" + elif [ $CHAN -lt 68586 ]; then + BAND="B70" + elif [ $CHAN -lt 68936 ]; then + BAND="B71" + elif [ $CHAN -lt 68986 ]; then + BAND="B72" + elif [ $CHAN -lt 69036 ]; then + BAND="B73" + elif [ $CHAN -lt 69466 ]; then + BAND="B74" + elif [ $CHAN -lt 70316 ]; then + BAND="B75" + elif [ $CHAN -lt 70366 ]; then + BAND="B76" + elif [ $CHAN -lt 70546 ]; then + BAND="B85" + elif [ $CHAN -lt 70596 ]; then + BAND="B87" + elif [ $CHAN -lt 70646 ]; then + BAND="B88" + else + BAND="-" + fi +} + +decode_nr5g() { + if [ $CHAN -lt 123400 ]; then + BAND="-" + elif [ $CHAN -le 130400 ]; then + BAND="n71" + elif [ $CHAN -lt 143400 ]; then + BAND="-" + elif [ $CHAN -lt 145600 ]; then + BAND="n29" + elif [ $CHAN -eq 145600 ]; then + BAND="n29|n85" + elif [ $CHAN -lt 145800 ]; then + BAND="n85" + elif [ $CHAN -eq 145800 ]; then + BAND="n12|n85" + elif [ $CHAN -lt 147600 ]; then + BAND="n12|n85" + elif [ $CHAN -lt 149200 ]; then + BAND="n12|n67|n85" + elif [ $CHAN -eq 149200 ]; then + BAND="n12|n13|n67|n85" + elif [ $CHAN -le 151200 ]; then + BAND="n13|n67" + elif [ $CHAN -lt 151600 ]; then + BAND="n67" + elif [ $CHAN -eq 151600 ]; then + BAND="n14|n28|n67" + elif [ $CHAN -le 153600 ]; then + BAND="n14|n28" + elif [ $CHAN -lt 158200 ]; then + BAND="n28" + elif [ $CHAN -eq 158200 ]; then + BAND="n14|n20|n28" + elif [ $CHAN -le 160600 ]; then + BAND="n20|n28" + elif [ $CHAN -le 164200 ]; then + BAND="n20" + elif [ $CHAN -lt 171800 ]; then + BAND="-" + elif [ $CHAN -lt 172000 ]; then + BAND="n26" + elif [ $CHAN -lt 173800 ]; then + BAND="n18|n26" + elif [ $CHAN -le 175000 ]; then + BAND="n5|n18|n26" + elif [ $CHAN -le 178800 ]; then + BAND="n5|n26" + elif [ $CHAN -lt 185000 ]; then + BAND="-" + elif [ $CHAN -le 192000 ]; then + BAND="n8" + elif [ $CHAN -lt 285400 ]; then + BAND="-" + elif [ $CHAN -lt 286400 ]; then + BAND="n51|n76|n91|n93" + elif [ $CHAN -eq 286400 ]; then + BAND="n50|n51|n75|n76|n91|92|n93|94" + elif [ $CHAN -lt 295000 ]; then + BAND="n50|n75|n92|n94" + elif [ $CHAN -eq 295000 ]; then + BAND="n50|n74|n75|n92|n94" + elif [ $CHAN -le 303400 ]; then + BAND="n50|n74|n75|n92|n94" + elif [ $CHAN -le 303600 ]; then + BAND="n74" + elif [ $CHAN -lt 305000 ]; then + BAND="-" + elif [ $CHAN -le 311800 ]; then + BAND="n24" + elif [ $CHAN -lt 361000 ]; then + BAND="-" + elif [ $CHAN -lt 376000 ]; then + BAND="n3" + elif [ $CHAN -eq 376000 ]; then + BAND="n3|n39" + elif [ $CHAN -le 384000 ]; then + BAND="n39" + elif [ $CHAN -lt 386000 ]; then + BAND="-" + elif [ $CHAN -le 398000 ]; then + BAND="n2|n25" + elif [ $CHAN -lt 399000 ]; then + BAND="n25" + elif [ $CHAN -eq 399000 ]; then + BAND="n25|n70" + elif [ $CHAN -lt 402000 ]; then + BAND="n70" + elif [ $CHAN -eq 402000 ]; then + BAND="n34|n70" + elif [ $CHAN -le 404000 ]; then + BAND="n34|n70" + elif [ $CHAN -le 405000 ]; then + BAND="n34" + elif [ $CHAN -lt 422000 ]; then + BAND="-" + elif [ $CHAN -le 434000 ]; then + BAND="n1|n65|n66" + elif [ $CHAN -le 440000 ]; then + BAND="n65|n66" + elif [ $CHAN -lt 460000 ]; then + BAND="-" + elif [ $CHAN -lt 470000 ]; then + BAND="n40" + elif [ $CHAN -eq 470000 ]; then + BAND="n30|n40" + elif [ $CHAN -le 472000 ]; then + BAND="n30|n40" + elif [ $CHAN -le 480000 ]; then + BAND="n40" + elif [ $CHAN -lt 496700 ]; then + BAND="-" + elif [ $CHAN -le 499000 ]; then + BAND="n53" + elif [ $CHAN -lt 499200 ]; then + BAND="-" + elif [ $CHAN -lt 514000 ]; then + BAND="n41|n90" + elif [ $CHAN -eq 514000 ]; then + BAND="n38|n41|n90" + elif [ $CHAN -lt 524000 ]; then + BAND="n38|n41|n90" + elif [ $CHAN -eq 524000 ]; then + BAND="n7|n38|n41|n90" + elif [ $CHAN -lt 538000 ]; then + BAND="n7|n41|n90" + elif [ $CHAN -eq 538000 ]; then + BAND="n7|n90" + elif [ $CHAN -lt 620000 ]; then + BAND="-" + elif [ $CHAN -lt 636667 ]; then + BAND="n77|n78" + elif [ $CHAN -le 646666 ]; then + BAND="n48|n77|n78" + elif [ $CHAN -le 653333 ]; then + BAND="n77|n78" + elif [ $CHAN -le 680000 ]; then + BAND="n77" + elif [ $CHAN -lt 693334 ]; then + BAND="-" + elif [ $CHAN -le 733333 ]; then + BAND="n79" + elif [ $CHAN -lt 743333 ]; then + BAND="-" + elif [ $CHAN -lt 795000 ]; then + BAND="n46" + elif [ $CHAN -eq 795000 ]; then + BAND="n46|n96" + elif [ $CHAN -le 875000 ]; then + BAND="n96" + else + BAND="-" + fi +} + +if [ -z "$CHAN" ]; then + BAND="-" +elif [ "$CHAN" -lt 123400 ]; then + decode_lte +elif [ "$CHAN" -le 875000 ]; then + decode_nr5g +else + BAND="-" +fi +echo $BAND +exit diff --git a/rooter/ext-rooter-basic/files/usr/bin/encodemask b/rooter/ext-rooter-basic/files/usr/bin/encodemask new file mode 100644 index 0000000..6b3ed14 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/bin/encodemask @@ -0,0 +1,24 @@ +#!/usr/bin/lua + +mtab = {} +vtab = {1, 2, 4, 8} + +for i = 1, 32 do + mtab[i] = 0 +end + +numarg = #arg +for argval = 1, numarg do + band = arg[argval] + if tonumber(band) <= 128 then + idx = math.floor((band - 1) / 4) + 1 + idxr = 33 - idx + val = vtab[(band - ((idx - 1) * 4 ))] + mtab[idxr] = mtab[idxr] + val + end +end +for i = 1, 32 do + mtab[i] = string.format("%X", mtab[i]) +end + +print(table.concat(mtab)) diff --git a/rooter/ext-rooter-basic/files/usr/bin/jkillall b/rooter/ext-rooter-basic/files/usr/bin/jkillall new file mode 100644 index 0000000..3802082 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/bin/jkillall @@ -0,0 +1,9 @@ +#!/bin/sh +LOOKFOR=$1 +KILLLIST=$(ps | grep $LOOKFOR) +echo "$KILLLIST" | while read line; do + if `echo "$line" | grep "/$LOOKFOR" > /dev/null` ; then + PIDV=$(echo $line | grep -o "^[0-9]\{1,5\}" | grep -o "[0-9]\{1,5\}") + kill $PIDV + fi +done \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/bin/rsrp2rssi b/rooter/ext-rooter-basic/files/usr/bin/rsrp2rssi new file mode 100644 index 0000000..06ad5b6 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/bin/rsrp2rssi @@ -0,0 +1,21 @@ +#!/usr/bin/lua + +rsrp = tonumber(arg[1]) +bw = tonumber(arg[2]) +if bw == 1.4 then + n = 6 +else + n = bw * 5 +end + +if tonumber(string.match(_VERSION, "%d+%.%d")) > 5.1 then + rssi = rsrp + (10 * math.log(n * 12, 10)) +else + rssi = rsrp + (10 * math.log10(n * 12)) +end +if rssi < -113 then + rssi = -113 +elseif rssi > -51 then + rssi = -51 +end +print(math.floor(rssi)) diff --git a/rooter/ext-rooter-basic/files/usr/bin/set_gpio b/rooter/ext-rooter-basic/files/usr/bin/set_gpio new file mode 100644 index 0000000..5fddfa7 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/bin/set_gpio @@ -0,0 +1,18 @@ +#!/bin/sh + +PIN=$1 +VALUE=$2 + +PIN_FILE=/sys/class/gpio/gpio$PIN + +if [ -z "$PIN" -o -z "$VALUE" ]; then + exit 1 +fi + +echo $PIN >/sys/class/gpio/export + +if [ $(cat $PIN_FILE/direction) = "out" ]; then + echo $VALUE >$PIN_FILE/value +fi + +echo $PIN >/sys/class/gpio/unexport \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/custom/locktype.sh b/rooter/ext-rooter-basic/files/usr/lib/custom/locktype.sh new file mode 100644 index 0000000..8d7f879 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/custom/locktype.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +CURRMODEM=$1 + +uVid=$(uci get modem.modem$CURRMODEM.uVid) +uPid=$(uci get modem.modem$CURRMODEM.uPid) + +if [ $uVid == "2c7c" ]; then + qc=$(uci get custom.atcmd.quectel) + echo "$qc" > /tmp/modemlock + echo " " >> /tmp/modemlock +else + if [ $uVid == "1199" ]; then + qc=$(uci get custom.atcmd.sierra) + echo "$qc" > /tmp/modemlock + echo " " >> /tmp/modemlock + else + qc=$(uci get custom.atcmd.generic) + echo "$qc" > /tmp/modemlock + echo " " >> /tmp/modemlock + fi +fi \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/custom/ttlx.sh b/rooter/ext-rooter-basic/files/usr/lib/custom/ttlx.sh new file mode 100644 index 0000000..79e52bd --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/custom/ttlx.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +log() { + logger -t "TTL Hack" "$@" +} + +cp -f /etc/firewall.user /etc/firewall.user.bk +sed /"#startTTL"/,/"#endTTL"/d /etc/firewall.user.bk > /etc/firewall.user +rm -f /etc/firewall.user.bk +/etc/init.d/firewall restart 2> /dev/null + diff --git a/rooter/ext-rooter-basic/files/usr/lib/gps/smsreply.sh b/rooter/ext-rooter-basic/files/usr/lib/gps/smsreply.sh new file mode 100644 index 0000000..9ca9af7 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/gps/smsreply.sh @@ -0,0 +1,115 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "GPS" "$@" +} + +CURRMODEM=$1 +SMSdest=$2 +MODTYPE=$(uci -q get modem.modem$CURRMODEM.modemtype) +if [ "$MODTYPE" == "2" -o "$MODTYPE" == "6" ]; then + COMMPORT="/dev/ttyUSB"$(uci -q get modem.modem$CURRMODEM.commport) +else + log "SMS position request from $SMSdest failed, modem $CURRMODEM is neither a Sierra nor Quectel" + exit +fi +GPSon=$(uci -q get gps.configuration.enabled) +if [ "$GPSon" != "1" -o $CURRMODEM == "2" ]; then + GPSon="0" + if [ $MODTYPE == "2" ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT!CUSTOM?") + GPSsel=$(echo $OX | grep "GPSSEL") + GPSenable=$(echo $OX | grep "GPSENABLE") + if [ -z "$GPSsel" -o -z "$GPSenable" ]; then + ATCMDD="AT!ENTERCND=\"A710\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if [ -z "$GPSsel" ]; then + ATCMDD="at!custom=\"GPSSEL\",1" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + if [ -z "$GPSenable" ]; then + ATCMDD="at!custom=\"GPSENABLE\",1" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ATCMDD="AT+CFUN=0;+CFUN=1,1" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + sleep 30 + fi + ATCMDD="AT!ENTERCND=\"AWRONG\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT!GPSTRACK=1,240,30,1000,5") + GPSendcmd="AT!GPSEND=0" + else + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+QGPS?") + err=$(echo "$OX" | grep "+QGPS: 1") + if [ -z "$err" ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+QGPS=1") + fi + ATCMDD="AT+QCFG=\"gpsdrx\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + err=$(echo "$OX" | grep "0") + if [ -n "$err" ]; then + ATCMDD="AT+QCFG=\"gpsdrx\",1" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + GPSendcmd="AT+QGPSEND" + fi +fi +SMStime=$(($(date +%s) + 120)) +LAT="" +LON="" +while true; do + if [ $MODTYPE == "2" ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT!GPSLOC?") + LATx=$(echo $OX | grep -o "Lat:[^(]\+([^)]\+" | grep -o "0x.\+") + LONx=$(echo $OX | grep -o "Lon:[^(]\+([^)]\+" | grep -o "0x.\+") + if [ -n "$LATx" -a -n "$LONx" ]; then + if [ $(printf "%d" $LATx) -gt $(printf "%d" 0x7FFFFFFF) ]; then + LATx=$(( ($LATx ^ 0xFFFFFFFF) + 1 )) + LAT="-"$(lua -e "print(string.format(\"%.5f\", $LATx * (180 / 2^25)))") + else + LAT=$(lua -e "print(string.format(\"%.5f\", $LATx * (180 / 2^25)))") + fi + if [ $(printf "%d" $LONx) -gt $(printf "%d" 0x7FFFFFFF) ]; then + LONx=$(( ($LONx ^ 0xFFFFFFFF) + 1 )) + LON="-"$(lua -e "print(string.format(\"%.5f\", $LONx * (180 / 2^25)))") + else + LON=$(lua -e "print(string.format(\"%.5f\", $LONx * (180 / 2^25)))") + fi + fi + else + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+QGPSLOC=2") + LAT=$(echo $OX | grep -o "+QGPSLOC:[ .0-9]\+,.\+" | cut -d, -f2) + LON=$(echo $OX | grep -o "+QGPSLOC:[ .0-9]\+,.\+" | cut -d, -f3) + fi + if [ -n "$LAT" -a -n "$LON" ]; then + SMSMODEM=$(uci -q get modem.general.smsnum) + if [ "$CURRMODEM" != "$SMSMODEM" ]; then + uci set modem.general.smsnum=$CURRMODEM + uci commit modem.general.smsnum + fi + OY=$(/usr/lib/sms/smsout.sh "$SMSdest" "$LAT $LON") + OYsent=$(echo $OY | grep -o "SMS sent") + if [ -n "$OYsent" ]; then + /usr/lib/sms/sys2sms.sh "ROOter" "GPS coordinates sent to $SMSdest" + log "GPS coordinates sent to $SMSdest" + else + log "Failed to send GPS coordinates sent to $SMSdest" + fi + if [ "$CURRMODEM" != "$SMSMODEM" ]; then + uci set modem.general.smsnum=$SMSMODEM + uci commit modem.general.smsnum + fi + break + fi + if [ $(date +%s) -gt $SMStime ]; then + log "Failed request from $SMSdest by SMS for LAT/LON, position not available" + break + fi + sleep 8 +done +if [ "$GPSon" != "1" ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$GPSendcmd") +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/admin/modem.lua b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/admin/modem.lua new file mode 100644 index 0000000..ae033c6 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/admin/modem.lua @@ -0,0 +1,664 @@ +module("luci.controller.admin.modem", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + entry({"admin", "modem"}, firstchild(), translate("移动数æ®"), 25).dependent=false + entry({"admin", "modem", "prof"}, cbi("rooter/profiles"), translate("DNS / APN / 监控é…ç½®"), 2) + entry({"admin", "modem", "nets"}, template("rooter/net_status"), translate("ä¿¡å·çŠ¶æ€ / 模å—状æ€"), 30) + entry({"admin", "modem", "debug"}, template("rooter/debug"), translate("åŽå°AT调试信æ¯"), 50) + entry({"admin", "modem", "cust"}, cbi("rooter/customize"), translate("自定义模å—端å£é…ç½®"), 55) + entry({"admin", "modem", "log"}, template("rooter/log"), translate("连接日志"), 60) + entry({"admin", "modem", "misc"}, template("rooter/misc"), translate("é”频段 / é”PCI / 切åè®®"), 40) + + entry({"admin", "modem", "block"}, + template("rooter/bandlock")) + + entry({"admin", "modem", "get_csq"}, call("action_get_csq")) + entry({"admin", "modem", "change_port"}, call("action_change_port")) + entry({"admin", "modem", "change_mode"}, call("action_change_mode")) + entry({"admin", "modem", "change_modem"}, call("action_change_modem")) + entry({"admin", "modem", "change_modemdn"}, call("action_change_modemdn")) + entry({"admin", "modem", "change_misc"}, call("action_change_misc")) + entry({"admin", "modem", "change_miscdn"}, call("action_change_miscdn")) + entry({"admin", "modem", "get_log"}, call("action_get_log")) + entry({"admin", "modem", "check_misc"}, call("action_check_misc")) + entry({"admin", "modem", "pwrtoggle"}, call("action_pwrtoggle")) + entry({"admin", "modem", "disconnect"}, call("action_disconnect")) + entry({"admin", "modem", "connect"}, call("action_connect")) + entry({"admin", "modem", "get_atlog"}, call("action_get_atlog")) + entry({"admin", "modem", "send_atcmd"}, call("action_send_atcmd")) + entry({"admin", "modem", "change_rate"}, call("action_change_rate")) + entry({"admin", "modem", "change_phone"}, call("action_change_phone")) + entry({"admin", "modem", "clear_log"}, call("action_clear_log")) + entry({"admin", "modem", "externalip"}, call("action_externalip")) + entry({"admin", "modem", "send_scancmd"}, call("action_send_scancmd")) + entry({"admin", "modem", "send_lockcmd"}, call("action_send_lockcmd")) + entry({"admin", "modem", "extping"}, call("action_extping")) + entry({"admin", "modem", "change_cell"}, call("action_change_cell")) + entry({"admin", "modem", "change_proto"}, call("action_change_proto")) + entry({"admin", "modem", "setpin"}, call("action_setpin")) +end + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +function action_get_atlog() + local file + local rv ={} + + file = io.open("/tmp/atlog", "r") + if file ~= nil then + local tmp = file:read("*all") + rv["log"] = tmp + file:close() + else + rv["log"] = "No entries in log file" + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_get_log() + local file + local rv ={} + + file = io.open("/usr/lib/rooter/log/connect.log", "r") + if file ~= nil then + local tmp = file:read("*all") + rv["log"] = tmp + file:close() + else + rv["log"] = translate("No entries in log file") + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_disconnect() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/rooter/connect/disconnect.sh") +end + +function action_connect() + local set = luci.http.formvalue("set") + miscnum = luci.model.uci.cursor():get("modem", "general", "miscnum") + os.execute("/tmp/links/reconnect" .. miscnum .. " " .. miscnum) +end + +function action_pwrtoggle() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/rooter/pwrtoggle.sh " .. set) +end + +function action_send_atcmd() + local rv ={} + modnum = luci.model.uci.cursor():get("modem", "general", "miscnum") + local file + local set = luci.http.formvalue("set") + fixed = string.gsub(set, "\"", "~") + os.execute("/usr/lib/rooter/luci/atcmd.sh \'" .. fixed .. "\'") + + result = "/tmp/result" .. modnum .. ".at" + file = io.open(result, "r") + if file ~= nil then + rv["result"] = file:read("*all") + file:close() + os.execute("/usr/lib/rooter/luci/luaops.sh delete /tmp/result" .. modnum .. ".at") + else + rv["result"] = " " + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_check_misc() + local rv ={} + local bnd1 = {} + local bnd2 = {} + local bnd31 = {} + local bnd32 = {} + local bnd33 = {} + local at1 = {} + local at2 = {} + local file + local file1 + local active + local connect + + miscnum = luci.model.uci.cursor():get("modem", "general", "miscnum") + conn = "Modem #" .. miscnum + rv["conntype"] = conn + empty = luci.model.uci.cursor():get("modem", "modem" .. miscnum, "empty") + if empty == "1" then + active = "0" + rv["netmode"] = "-" + else + active = luci.model.uci.cursor():get("modem", "modem" .. miscnum, "active") + if active == "1" then + connect = luci.model.uci.cursor():get("modem", "modem" .. miscnum, "connected") + if connect == "0" then + active = "1" + else + active = "2" + end + uVid = luci.model.uci.cursor():get("modem", "modem" .. miscnum, "uVid") + rv["uVid"] = uVid + uPid = luci.model.uci.cursor():get("modem", "modem" .. miscnum, "uPid") + rv["uPid"] = uPid + file = io.open("/etc/fake", "r") + if file == nil then + rv["fake"] = "0" + else + rv["fake"] = "1" + file:close() + end + + rv["cenable"] = luci.model.uci.cursor():get("custom", "bandlock", "cenable" .. miscnum) + if rv["cenable"] == nil then + rv["cenable"] = "0" + end + rv["earfcn"] = luci.model.uci.cursor():get("custom", "bandlock", "earfcn" .. miscnum) + if rv["earfcn"] == nil then + rv["earfcn"] = "0" + end + rv["pci"] = luci.model.uci.cursor():get("custom", "bandlock", "pci" .. miscnum) + if rv["pci"] == nil then + rv["pci"] = "0" + end + + rv["earfcn1"] = luci.model.uci.cursor():get("custom", "bandlock", "earfcn1" .. miscnum) + if rv["earfcn1"] == nil then + rv["earfcn1"] = "0" + end + rv["pci1"] = luci.model.uci.cursor():get("custom", "bandlock", "pci1" .. miscnum) + if rv["pci1"] == nil then + rv["pci1"] = "0" + end + + rv["earfcn2"] = luci.model.uci.cursor():get("custom", "bandlock", "earfcn2" .. miscnum) + if rv["earfcn2"] == nil then + rv["earfcn2"] = "0" + end + rv["pci2"] = luci.model.uci.cursor():get("custom", "bandlock", "pci2" .. miscnum) + if rv["pci2"] == nil then + rv["pci2"] = "0" + end + + rv["earfcn3"] = luci.model.uci.cursor():get("custom", "bandlock", "earfcn3" .. miscnum) + if rv["earfcn3"] == nil then + rv["earfcn3"] = "0" + end + rv["pci3"] = luci.model.uci.cursor():get("custom", "bandlock", "pci3" .. miscnum) + if rv["pci3"] == nil then + rv["pci3"] = "0" + end + + file = io.open("/tmp/bmask", "r") + if file == nil then + rv["bndstr"] = "0" + rv["bndsup"] = "0" + else + line = file:read("*line") + rv["bndstr"] = line + line = file:read("*line") + rv["bndstr5g"] = line + line = file:read("*line") + rv["bndstr5gsa"] = line + line = file:read("*line") + rv["bndsup"] = line + line = file:read("*line") + rv["bndsup5g"] = line + line = file:read("*line") + rv["bndsup5gsa"] = line + line = file:read("*line") + ca = line + if ca ~= nil then + line = file:read("*line") + ca3 = line + end + file:close() + + indx = 0 + if ca ~= nil then + file = io.open("/usr/lib/rooter/luci/" .. ca, "r") + if file ~= nil then + line = file:read("*line") + repeat + s, e = line:find(" ") + b1 = trim(line:sub(1, s-1)) + bnd1[indx] = b1 + b2 = trim(line:sub(s+1)) + bnd2[indx] = b2 + indx = indx +1 + line = file:read("*line") + until line == nil + file:close() + end + end + rv['b1'] = bnd1 + rv['b2'] = bnd2 + rv['indx'] = tostring(indx) + + indx3 = 0 + if ca3 ~= nil then + file = io.open("/usr/lib/rooter/luci/" .. ca3, "r") + if file ~= nil then + line = file:read("*line") + repeat + s, e = line:find(" ") + b1 = trim(line:sub(1, s-1)) + bnd31[indx3] = b1 + cs, ce = line:find(" ", s+1) + b2 = trim(line:sub(s+1, cs-1)) + bnd32[indx3] = b2 + b3 = trim(line:sub(cs+1)) + bnd33[indx3] = b3 + indx3 = indx3 +1 + line = file:read("*line") + until line == nil + file:close() + end + end + rv['b31'] = bnd31 + rv['b32'] = bnd32 + rv['b33'] = bnd33 + rv['indx3'] = tostring(indx3) + + end + end + netmode = luci.model.uci.cursor():get("modem", "modem" .. miscnum, "netmode") + rv["netmode"] = netmode + end + rv["pin"] = luci.model.uci.cursor():get("modem", "general", "pin") + rv["plock"] = luci.model.uci.cursor():get("custom", "atcmd", "lock") + if rv["plock"] == "1" then + rv["atlock"] = luci.model.uci.cursor():get("custom", "menu", "full") + generic = luci.model.uci.cursor():get("custom", "atcmd", "generic") + aindx = 0 + if active == "0" then + file = io.open(generic, "r") + else + os.execute("/usr/lib/custom/locktype.sh " .. miscnum ) + file1 = io.open("/tmp/modemlock", "r") + if file1 ~= nil then + linex = file1:read("*line") + file1:close() + file = io.open(linex, "r") + else + file = io.open(generic, "r") + end + end + if file ~= nil then + line = file:read("*line") + repeat + at1[aindx] = line + line = file:read("*line") + at2[aindx] = line + aindx = aindx +1 + line = file:read("*line") + until line == nil + file:close() + rv['at1'] = at1 + rv['at2'] = at2 + rv['aindx'] = tostring(aindx) + end + end + rv["active"] = active + file = io.open("/tmp/gpiopin", "r") + if file == nil then + rv.gpio = "0" + else + rv.gpio = "1" + line = file:read("*line") + line = file:read("*line") + if line ~= nil then + rv.gpio = "2" + end + file:close() + end + file = io.open("/sys/bus/usb/drivers/usb/usb1", "r") + if file == nil then + rv["usb"] = "0" + else + io.close(file) + rv["usb"] = "1" + end + file = io.open("/sys/bus/usb/drivers/usb/usb2", "r") + if file ~= nill then + io.close(file) + rv["usb"] = "2" + end + proto = luci.model.uci.cursor():get("modem", "modem" .. miscnum, "proto") + rv["proto"] = proto + + model = luci.model.uci.cursor():get("modem", "modem" .. miscnum, "model") + rv["model"] = model + + celltype = luci.model.uci.cursor():get("modem", "modem" .. miscnum, "celltype") + rv["celltype"] = celltype + cmode = luci.model.uci.cursor():get("modem", "modem" .. miscnum, "cmode") + if cmode == "0" then + rv["netmode"] = "10" + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function lshift(x, by) + return x * 2 ^ by +end + +function rshift(x, by) + return math.floor(x / 2 ^ by) +end + +function action_change_mode() + local set = tonumber(luci.http.formvalue("set")) + local modemtype = rshift(set, 4) + local temp = lshift(modemtype, 4) + local netmode = set - temp + os.execute("/usr/lib/rooter/luci/modechge.sh " .. modemtype .. " " .. netmode) +end + +function action_change_port() + local set = tonumber(luci.http.formvalue("set")) + if set ~= nil and set > 0 then + if set == 1 then + os.execute("/usr/lib/rooter/luci/portchge.sh dwn") + else + os.execute("/usr/lib/rooter/luci/portchge.sh up") + end + end +end + +function action_change_misc() + os.execute("/usr/lib/rooter/luci/modemchge.sh misc 1") +end + +function action_change_miscdn() + os.execute("/usr/lib/rooter/luci/modemchge.sh misc 0") +end + +function action_change_modem() + os.execute("/usr/lib/rooter/luci/modemchge.sh modem 1") +end + +function action_change_modemdn() + os.execute("/usr/lib/rooter/luci/modemchge.sh modem 0") +end + +function action_get_csq() + modnum = luci.model.uci.cursor():get("modem", "general", "modemnum") + local file + stat = "/tmp/status" .. modnum .. ".file" + file = io.open(stat, "r") + + local rv ={} + + rv["port"] = file:read("*line") + rv["csq"] = file:read("*line") + rv["per"] = file:read("*line") + rv["rssi"] = file:read("*line") + rv["modem"] = file:read("*line") + rv["cops"] = file:read("*line") + rv["mode"] = file:read("*line") + rv["lac"] = file:read("*line") + rv["lacn"] = file:read("*line") + rv["cid"] = file:read("*line") + rv["cidn"] = file:read("*line") + rv["mcc"] = file:read("*line") + rv["mnc"] = file:read("*line") + rv["rnc"] = file:read("*line") + rv["rncn"] = file:read("*line") + rv["down"] = file:read("*line") + rv["up"] = file:read("*line") + rv["ecio"] = file:read("*line") + rv["rscp"] = file:read("*line") + rv["ecio1"] = file:read("*line") + rv["rscp1"] = file:read("*line") + rv["netmode"] = file:read("*line") + rv["cell"] = file:read("*line") + rv["modtype"] = file:read("*line") + rv["conntype"] = file:read("*line") + rv["channel"] = file:read("*line") + rv["phone"] = file:read("*line") + file:read("*line") + rv["lband"] = file:read("*line") + rv["tempur"] = file:read("*line") + rv["proto"] = file:read("*line") + rv["pci"] = file:read("*line") + rv["sinr"] = file:read("*line") + --rv["lat"] = file:read("*line") + --rv["long"] = file:read("*line") + + file:close() + + cmode = luci.model.uci.cursor():get("modem", "modem" .. modnum, "cmode") + if cmode == "0" then + rv["netmode"] = "10" + end + + rssi = rv["rssi"] + ecio = rv["ecio"] + rscp = rv["rscp"] + ecio1 = rv["ecio1"] + rscp1 = rv["rscp1"] + + if ecio == nil then + ecio = "-" + end + if ecio1 == nil then + ecio1 = "-" + end + if rscp == nil then + rscp = "-" + end + if rscp1 == nil then + rscp1 = "-" + end + + if ecio ~= "-" then + rv["ecio"] = ecio .. " dB" + end + if rscp ~= "-" then + rv["rscp"] = rscp .. " dBm" + end + if ecio1 ~= " " then + rv["ecio1"] = " (" .. ecio1 .. " dB)" + end + if rscp1 ~= " " then + rv["rscp1"] = " (" .. rscp1 .. " dBm)" + end + + if not nixio.fs.access("/etc/netspeed") then + rv["crate"] = translate("快速(æ¯10秒更新一次)") + else + rv["crate"] = translate("缓慢(æ¯60秒更新一次)") + end + + stat = "/tmp/msimdata" .. modnum + file = io.open(stat, "r") + if file == nil then + rv["modid"] = " " + rv["imei"] = " " + rv["imsi"] = " " + rv["iccid"] = " " + rv["host"] = "0" + else + rv["modid"] = file:read("*line") + rv["imei"] = file:read("*line") + rv["imsi"] = file:read("*line") + rv["iccid"] = file:read("*line") + rv["host"] = file:read("*line") + file:close() + end + + gpsdata = "/tmp/gpsdata1" + file = io.open(gpsdata, "r") + if file == nil then + rv["lat"] = "-" + rv["long"] = "-" + else + rv["lat"] = file:read("*line") + rv["long"] = file:read("*line") + file:close() + end + + stat = "/tmp/msimnum" .. modnum + file = io.open(stat, "r") + if file == nil then + rv["phone"] = "-" + rv["phonen"] = " " + else + rv["phone"] = file:read("*line") + rv["phonen"] = file:read("*line") + file:close() + end + + stat = "/tmp/simpin" .. modnum + file = io.open(stat, "r") + if file == nil then + rv["simerr"] = "0" + else + typ = file:read("*line") + if typ == "0" then + rv["simerr"] = "1" + else + if typ == "1" then + rv["simerr"] = "2" + else + if typ == "2" then + rv["simerr"] = "3" + else + rv["simerr"] = "4" + end + end + end + file:close() + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_change_rate() + local set = luci.http.formvalue("set") + if set == "1" then + os.execute("rm -f /etc/netspeed") + else + os.execute("echo \"0\" > /etc/netspeed") + end +end + +function action_change_phone() + local set = luci.http.formvalue("set") + s, e = string.find(set, "|") + pno = string.sub(set, 1, s-1) + pnon = string.sub(set, e+1) + modnum = luci.model.uci.cursor():get("modem", "general", "modemnum") + os.execute("/usr/lib/rooter/common/phone.sh " .. modnum .. " " .. pno .. " \"" .. pnon .. "\"") +end + +function action_clear_log() + local file + file = io.open("/usr/lib/rooter/log/connect.log", "w") + file:close() + os.execute("/usr/lib/rooter/log/logger 'Connection Log Cleared by User'") +end + +function action_externalip() + local rv ={} + + os.execute("rm -f /tmp/ipip; wget -O /tmp/ipip http://ipecho.net/plain > /dev/null 2>&1") + file = io.open("/tmp/ipip", "r") + if file == nil then + rv["extip"] = translate("Not Available") + else + rv["extip"] = file:read("*line") + if rv["extip"] == nil then + rv["extip"] = translate("Not Available") + end + file:close() + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_send_scancmd() + local rv ={} + local file + os.execute("/usr/lib/rooter/luci/scancmd.sh") + + result = "/tmp/scan" + file = io.open(result, "r") + if file ~= nil then + rv["result"] = file:read("*all") + file:close() + os.execute("/usr/lib/rooter/luci/luaops.sh delete /tmp/scan") + else + rv["result"] = " " + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_send_lockcmd() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/rooter/luci/lock.sh " .. set) +end + +function action_extping() + local rv ={} + + enable = luci.model.uci.cursor():get("ping", "ping", "enable") + if enable == "0" then + rv["extping"] = translate("Not Enabled") + else + conn = luci.model.uci.cursor():get("ping", "ping", "conn") + if conn == "1" then + rv["extping"] = translate("Enabled, Waiting for Modem to Connect") + else + if conn == "2" then + rv["extping"] = translate("Enabled, Ping Test was Good") + else + if conn == "3" then + rv["extping"] = translate("Enabled, Ping Test Failed, Restarting Modem, Waiting for Reconnection") + else + if conn == "4" then + rv["extping"] = translate("Enabled, Connected, Waiting for Ping Test") + else + rv["extping"] = translate("Enabled, Unknown State") + end + end + end + end + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end + +function action_change_cell() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/rooter/luci/setcell.sh " .. "\"" .. set .. "\"") +end + +function action_change_proto() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/rooter/luci/protochnge.sh " ..set) +end + +function action_setpin() + local set = luci.http.formvalue("set") + os.execute("uci set modem.general.pin=" .. set .. "; uci commit modem") +end + diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/modlog.lua b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/modlog.lua new file mode 100644 index 0000000..b37f797 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/modlog.lua @@ -0,0 +1,29 @@ +module("luci.controller.modlog", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + page = entry({"admin", "modem", "modlog"}, template("modlog/modlog"), _(translate("模å—连接日志信æ¯")), 61) + page.dependent = true + + entry({"admin", "status", "modlog"}, call("action_modlog")) +end + +function action_modlog() + local file + local rv ={} + + file = io.open("/tmp/modlog.log", "r") + if file ~= nil then + local tmp = file:read("*all") + rv["log"] = tmp + file:close() + else + rv["log"] = translate("No entries in log file") + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/poweroff.lua b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/poweroff.lua new file mode 100644 index 0000000..62918f2 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/poweroff.lua @@ -0,0 +1,16 @@ +module("luci.controller.poweroff", package.seeall) + +I18N = require "luci.i18n" +translate = I18N.translate + +function index() + local page + page = entry({"admin", "system", "poweroff"}, template("admin_system/poweroff"), _(translate("System Stop")), 95) + entry({"admin", "system", "do_poweroff"}, call("action_poweroff")) + page.dependent = true +end + +function action_poweroff() + local set = luci.http.formvalue("set") + os.execute("/usr/lib/rooter/shutall.sh") +end diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/profile.lua b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/profile.lua new file mode 100644 index 0000000..fce9b46 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/controller/profile.lua @@ -0,0 +1,40 @@ +module("luci.controller.profile", package.seeall) +function index() + entry({"admin", "profile", "savecfg"}, call("action_savecfg")) + entry({"admin", "profile", "loadcfg"}, call("action_loadcfg")) + entry({"admin", "profile", "loadcfg1"}, call("action_loadcfg1")) + entry({"admin", "profile", "loadcfg2"}, call("action_loadcfg2")) +end + +function action_savecfg() + os.execute('/usr/lib/profile/savecfg.sh') +end + +function action_loadcfg() + local set = luci.http.formvalue("set") + local set1 = luci.http.formvalue("set1") + local tfile = io.open("/tmp/profilename", "w") + tfile:write(set, "\n") + if set1 ~= "~~" then + tfile:write(set1, "\n") + end + tfile:close() + os.execute("/usr/lib/profile/loadcfg.sh") +end + +function action_loadcfg1() + local set = luci.http.formvalue("set") + local tfile = io.open("/tmp/profilename", "w") + tfile:write(set) + tfile:close() +end + +function action_loadcfg2() + local set1 = luci.http.formvalue("set1") + if set1 ~= "~~" then + local tfile = io.open("/tmp/profilename", "a") + tfile:write(set1) + tfile:close() + end + os.execute("/usr/lib/profile/loadcfg.sh") +end \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/firewall/ttlx.lua b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/firewall/ttlx.lua new file mode 100644 index 0000000..dcecccb --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/firewall/ttlx.lua @@ -0,0 +1,30 @@ +local utl = require "luci.util" +local uci = require "luci.model.uci".cursor() + +m = Map("ttl", translate("Firewall - Custom TTL Settings"), + translate("Enable and use a custom TTL value with modems")) + +m.on_after_save = function(self) + --luci.sys.call("/usr/lib/custom/ttlx.sh &") +end + +gw = m:section(TypedSection, translate("ttl"), translate("Settings")) +gw.anonymous = true + +en = gw:option(Flag, "enabled", translate("Enabled :"), translate("Enable the use of custom TTL value")); +en.default="0" +en.rmempty = false; +en.optional=false; + +val = gw:option(ListValue, "value", translate("TTL Value :"), translate("Custom TTL value to be used on modems")); +val.default="65" +val:depends("enabled", "1") +val:value("63", "63") +val:value("64", "64") +val:value("65", "65") +val:value("66", "66") +val:value("67", "67") +val:value("117", "117") +val:value("0", "TTL-INC 1") + +return m \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/rooter/customize.lua b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/rooter/customize.lua new file mode 100644 index 0000000..acc7eb5 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/rooter/customize.lua @@ -0,0 +1,156 @@ +local utl = require "luci.util" + +local modemfile = "/etc/config/modem.data" +local modemdata = {} +local count +local tabdata = {} + +function process_line(xline, cnt) + local data = {} + local pline = xline + local start = 1 + for i=1,3 do + s, e = string.find(pline, " ") + data[i] = string.sub(pline, start, s-1) + pline = string.sub(pline, e+1) + end + data[4] = pline + modemdata[cnt] = data +end + +function read_modem() + count = 0 + local file = io.open(modemfile, "r") + if file == nil then + return + end + repeat + local line = file:read("*line") + if line == nil then + break + end + if string.len(line) < 5 then + break + end + count = count + 1 + process_line(line, count) + until 1==0 + file:close() +end + +function insert_modem() + local location = count + 1 + + if count > 0 then + for j=1,count do + local mdata = modemdata[j] + if mdata[1] == tabdata[1] and mdata[2] == tabdata[2] then + location = j + end + end + end + + if count == 0 then + count = 1 + else + if location > count then + count = count + 1 + end + end + modemdata[location] = tabdata +end + +function write_modem() + os.remove(modemfile) + local file = io.open(modemfile, "w") + for k=1,count do + local mdata = modemdata[k] + for l=1,3 do + file:write(mdata[l], " ") + end + file:write(mdata[4], "\n") + end + file:close() +end + +function process_tabdata() + if tabdata[1] ~= "nil" and tabdata[2] ~= "nil" then + read_modem() + insert_modem() + write_modem() + end +end + +m = Map("modem", translate("自定义4G/5G æ¨¡å—æ”¯æŒ"), translate(" 修改æŸä¸ªæ¨¡å—使用的通信端å£")) + +m.on_after_commit = function(self) + -- all written config names are in self.parsechain + local sobj + for _, sobj in ipairs(self.children) do + local sids + if utl.instanceof(sobj, NamedSection) then + sids = { sobj.section } + elseif utl.instanceof(sobj, TypedSection) then + sids = sobj:cfgsections() + end + local sid, fld, fln + + if not utl.instanceof(sobj, SimpleSection) then + for _, sid in ipairs(sids) do + for fln, fld in ipairs(sobj.children) do + local val = fld:formvalue(sid) + if val == nil or string.len(val) == 0 then + val = "nil" + end + tabdata[fln] = val + end + end + end + end + process_tabdata() +end + +-- +-- Vid Pid Dataport Commport +-- + +e = m:section(TypedSection, "new", translate("模å—ç«¯å£ :")) + +a1 = e:option(Value, "vid", translate("æ¨¡å— VID:")); +a1.optional=false; + +b1 = e:option(Value, "pid", translate("æ¨¡å— ID :")); +b1.optional=false; + +p3 = e:option(ListValue, "port", translate("PPP 拨å·ç«¯å£ :")) +p3:value("tty", "default") +p3:value("tty0", "/dev/ttyUSB0") +p3:value("tty1", "/dev/ttyUSB1") +p3:value("tty2", "/dev/ttyUSB2") +p3:value("tty3", "/dev/ttyUSB3") +p3:value("tty4", "/dev/ttyUSB4") +p3:value("tty5", "/dev/ttyUSB5") +p3.default = "tty" + +p4 = e:option(ListValue, "comm", translate("é€šè®¯ç«¯å£ :")) +p4:value("tty", "default") +p4:value("tty0", "/dev/ttyUSB0") +p4:value("tty1", "/dev/ttyUSB1") +p4:value("tty2", "/dev/ttyUSB2") +p4:value("tty3", "/dev/ttyUSB3") +p4:value("tty4", "/dev/ttyUSB4") +p4:value("tty5", "/dev/ttyUSB5") +p4.default = "tty" + +b3 = e:option(DummyValue, "blank", " "); + +btn = e:option(Button, "_btn", translate(" ")) +btn.inputtitle = translate("删除模å—端å£é…ç½®") +btn.inputstyle = "apply" +function btn.write() + luci.sys.call("/usr/lib/rooter/luci/luaops.sh delete /etc/config/modem.data") +end + +m:section(SimpleSection).template = "rooter/custom" + +return m diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/rooter/profiles.lua b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/rooter/profiles.lua new file mode 100644 index 0000000..89789eb --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/model/cbi/rooter/profiles.lua @@ -0,0 +1,828 @@ +local utl = require "luci.util" +local uci = require "luci.model.uci".cursor() +local sys = require "luci.sys" +local fs = require "nixio.fs" + +local maxmodem = luci.model.uci.cursor():get("modem", "general", "max") +local profsave = luci.model.uci.cursor():get("custom", "profile", "save") +if profsave == nil then + profsave ="0" +end +local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0" +local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0" + +m = Map("profile", translate("模å—DNS / APN é…ç½®"),translate("")) + +m.on_after_commit = function(self) + if profsave == "1" then + luci.sys.call("/usr/lib/profile/restart.sh &") + end +end + +if profsave == "1" then + m:section(SimpleSection).template = "rooter/profile" + ds = m:section(TypedSection, "simpin", translate("SIMå¡Pinç  :"), translate("如果é…置文件钟没有SIM PINç åˆ™ä½¿ç”¨")) + ds.anonymous = true + + ms = ds:option(Value, "pin", translate("PIN :")); + ms.rmempty = true; + ms.default = "" +end + + +-- +-- Default profile +-- + +di = m:section(TypedSection, "default", translate("默认"), translate("一般åªéœ€è¦å¡«å†™æ‚¨è¿è¥å•†çš„APNå³å¯ï¼Œä¸€èˆ¬å·²ç»è‡ªåŠ¨åŠ è½½è¯†åˆ«äº†ï¼Œå¥‡è‘©è™šæ‹Ÿè¿è¥å•†ä½ ä¹Ÿå¯ä»¥ç»§ç»­å¡« Tips:模å—下次é‡è¿žåŽç”Ÿæ•ˆï¼Œå¦‚果你è¦çŽ°åœ¨ç”Ÿæ•ˆï¼Œè¯·ä¿å­˜åŽé‡å¯æ¨¡å—)## åŽä¸ºå¤©é™…通5G SA APN:5gscuiot ##")) +di.anonymous = true +di:tab("default", translate("通用")) +di:tab("advance", translate("高级")) +di:tab("connect", translate("连接状æ€ç›‘控")) +if (multilock == "0") or (multilock == "1" and rootlock == "1") then + di:tab("bwidth", translate("Bandwidth Reporting频宽报告")) +end + +this_tab = "default" + +ma = di:taboption(this_tab, Value, "apn", "APN :"); +ma.rmempty = true; +ma.default = "broadband" + +tt = di:taboption(this_tab, ListValue, "ttl", translate("设定TTL值 :")) +tt:value("0", translate("使用当å‰å€¼")) +tt:value("1", translate("ä¸é…ç½®TTL值")) +tt:value("63", "TTL 63") +tt:value("64", "TTL 64") +tt:value("65", "TTL 65") +tt:value("66", "TTL 66") +tt:value("67", "TTL 67") +tt:value("117", "TTL 117") +tt:value("TTL-INC 1", "TTL-INC 1") +tt.default = "0" + +ynl = di:taboption(this_tab, ListValue, "hostless", translate("设定通信模å—TTL")); +ynl:value("0", "å¦") +ynl:value("1", translate("是")) +ynl.default=0 + +pt = di:taboption(this_tab, ListValue, "pdptype", translate("IPå议类型 :")) +pt:value("IP", "IPv4") +pt:value("IPV6", "IPv6") +pt:value("IPV4V6", "IPv4+IPv6") +pt:value("0", "默认") +pt.default = "0" + +cmcc = di:taboption(this_tab, Value, "context", translate("PDP Context for APN :")); +cmcc.optional=false; +cmcc.rmempty = true; +cmcc.datatype = "and(uinteger,min(1),max(10))" +cmcc.default = "1" + +mu = di:taboption(this_tab, Value, "user", translate("用户å :")); +mu.optional=false; +mu.rmempty = true; + +mp = di:taboption(this_tab, Value, "passw", translate("å¯†ç  :")); +mp.optional=false; +mp.rmempty = true; +mp.password = true + +mpi = di:taboption(this_tab, Value, "pincode", translate("PINç  :")); +mpi.optional=false; +mpi.rmempty = true; + +mau = di:taboption(this_tab, ListValue, "auth", translate("身份验è¯ç±»åž‹ :")) +mau:value("0", "None") +mau:value("1", "PAP") +mau:value("2", "CHAP") +mau.default = "0" + +mtz = di:taboption(this_tab, ListValue, "tzone", translate("自动设置时区"), translate("Tips:就是模å—通网åŽä¼šè‡ªåŠ¨è®¾ç½®æ—¶åŒº")); +mtz:value("0", "çªä¸è¦") +mtz:value("1", translate("çªè¦")) +mtz.default=1 + +ml = di:taboption(this_tab, ListValue, "lock", translate("阻止国际漫游选项并é”定特定è¿è¥å•† :")); +ml:value("0", translate("å¦")) +ml:value("1", translate("强硬")) +ml:value("2", translate("软弱")) +ml.default=0 + +mcc = di:taboption(this_tab, Value, "mcc", translate("MCC :")); +mcc.optional=false; +mcc.rmempty = true; +mcc.datatype = "and(uinteger,min(1),max(999))" +mcc:depends("lock", "1") +mcc:depends("lock", "2") + +mnc = di:taboption(this_tab, Value, "mnc", translate("MNC :")); +mnc.optional=false; +mnc.rmempty = true; +mnc.datatype = "and(uinteger,min(1),max(999))" +mnc:depends("lock", "1") +mnc:depends("lock", "2") + +this_taba = "advance" + +mf = di:taboption(this_taba, ListValue, "ppp", translate("ä¸ä½¿ç”¨å¸¸è§„å议,强制使用PPP拨å·åè®® :")); +mf:value("0", translate("å¯ç”¨")) +mf:value("1", translate("ç¦ç”¨")) +mf.default=0 + +md = di:taboption(this_taba, Value, "delay", translate("连接延时(秒为å•ä½) :")); +md.optional=false; +md.rmempty = false; +md.default = 5 +md.datatype = "and(uinteger,min(5))" + +nl = di:taboption(this_taba, ListValue, "nodhcp", translate("强制QMIåè®®ä¸ä½¿ç”¨æ¨¡å—çš„DHCP,从其他ä½ç½®èŽ·å– :")); +nl:value("0", translate("ç¦ç”¨")) +nl:value("1", translate("å¯ç”¨")) +nl.default=0 + +mdns1 = di:taboption(this_taba, Value, "dns1", translate("自定义DNS 1 :")); +mdns1.rmempty = true; +mdns1.optional=false; +mdns1.datatype = "ipaddr" + +mdns2 = di:taboption(this_taba, Value, "dns2", translate("自定义DNS 2 :")); +mdns2.rmempty = true; +mdns2.optional=false; +mdns2.datatype = "ipaddr" + +mdns3 = di:taboption(this_taba, Value, "dns3", translate("自定义DNS 3 :")); +mdns3.rmempty = true; +mdns3.optional=false; +mdns3.datatype = "ipaddr" + +mdns4 = di:taboption(this_taba, Value, "dns4", translate("自定义DNS 4 :")); +mdns4.rmempty = true; +mdns4.optional=false; +mdns4.datatype = "ipaddr" + + +mlog = di:taboption(this_taba, ListValue, "log", translate("å¯ç”¨AT连接日志 :")); +mlog:value("0", translate("ç¦ç”¨")) +mlog:value("1", translate("是")) +mlog.default=0 + +if nixio.fs.access("/etc/config/mwan3") then + mlb = di:taboption(this_taba, ListValue, "lb", translate("在多个5G模å—䏭开坿µé‡è´Ÿè½½å‡è¡¡ :")); + mlb:value("0", translate("ç¦ç”¨")) + mlb:value("1", translate("å¯ç”¨")) + mlb.default=0 +end + +mtu = di:taboption(this_taba, Value, "mtu", translate("自定义MTU值 :"), + translate("ä¸å»ºè®®ä¹±æ•´ï¼Œåªèƒ½è‡ªå®šä¹‰1420到1500的范围的值")); +mtu.optional=true +mtu.rmempty = true +mtu.default = "1500" +mtu.datatype = "range(1420, 1500)" + +mat = di:taboption(this_taba, ListValue, "at", translate("连接时å‘é€è‡ªå®šä¹‰AT命令 :")); +mat:value("0", translate("ç¦ç”¨")) +mat:value("1", translate("å¯ç”¨")) +mat.default=0 + +matc = di:taboption(this_taba, Value, "atc", translate("è¦æ‰§è¡Œçš„AT命令 :")); +matc.optional=false; +matc.rmempty = true; + +-- +-- Default Connection Monitoring +-- + +this_tab = "connect" + +alive = di:taboption(this_tab, ListValue, "alive", translate("连接状æ€ç›‘控 :")); +alive.rmempty = true; +alive:value("0", translate("ç¦ç”¨")) +alive:value("1", translate("å¯ç”¨æŽ‰çº¿å†™å…¥ç³»ç»Ÿæ—¥å¿—")) +alive:value("2", translate("å¯ç”¨ 5Gæ¨¡å—æŽ‰çº¿ 则 路由自动é‡å¯")) +alive:value("3", translate("å¯ç”¨ 5Gæ¨¡å—æŽ‰çº¿ 则 è‡ªåŠ¨é‡æ‹¨")) +alive:value("4", translate("å¯ç”¨ 5Gæ¨¡å—æŽ‰çº¿ 则 釿–°ä¸Šç”µæ¨¡å—,需è¦è·¯ç”±GPIO支æŒï¼Œå¦åˆ™å°†ä½¿ç”¨å…¶ä»–æ–¹å¼é‡è¿ž")) +alive.default=0 + +reliability = di:taboption(this_tab, Value, "reliability", translate("监测网络稳定性 :"), + translate("范围: 1-100,必须Ping通这些IP地å€ï¼Œè¿™æ¡é€šä¿¡é“¾è·¯æ‰ä¼šè¢«è§†ä¸ºè”网状æ€")) +reliability.datatype = "range(1, 100)" +reliability.default = "1" +reliability:depends("alive", "1") +reliability:depends("alive", "2") +reliability:depends("alive", "3") +reliability:depends("alive", "4") + +count = di:taboption(this_tab, ListValue, "count", translate("监测次数(Ping) :")) +count.default = "1" +count:value("1") +count:value("2") +count:value("3") +count:value("4") +count:value("5") +count:depends("alive", "1") +count:depends("alive", "2") +count:depends("alive", "3") +count:depends("alive", "4") + +interval = di:taboption(this_tab, ListValue, "pingtime", translate("监测时间间隔 (Ping) :"), + translate("监测Ping之间间隔时间的值")) +interval.default = "10" +interval:value("5", translate("5 ç§’/次")) +interval:value("10", translate("10 ç§’/次")) +interval:value("20", translate("20 ç§’/次 推è")) +interval:value("30", translate("30 秒次")) +interval:value("60", translate("1 分钟/次 ")) +interval:value("300", translate("5 分钟/次")) +interval:value("600", translate("10 分钟/次")) +interval:value("900", translate("15 分钟/次")) +interval:value("1800", translate("30 分钟/次")) +interval:value("3600", translate("1 å°æ—¶/次")) +interval:depends("alive", "1") +interval:depends("alive", "2") +interval:depends("alive", "3") +interval:depends("alive", "4") + +timeout = di:taboption(this_tab, ListValue, "pingwait", translate("Ping è¶…æ—¶ :")) +timeout.default = "2" +timeout:value("1", translate("1 ç§’")) +timeout:value("2", translate("2 ç§’")) +timeout:value("3", translate("3 ç§’")) +timeout:value("4", translate("4 ç§’")) +timeout:value("5", translate("5 ç§’")) +timeout:value("6", translate("6 ç§’")) +timeout:value("7", translate("7 ç§’")) +timeout:value("8", translate("8 ç§’")) +timeout:value("9", translate("9 ç§’")) +timeout:value("10", translate("10 ç§’")) +timeout:depends("alive", "1") +timeout:depends("alive", "2") +timeout:depends("alive", "3") +timeout:depends("alive", "4") + +packetsize = di:taboption(this_tab, Value, "packetsize", translate("Ping报文大å°(字节为å•ä½) :"), + translate("范围值 :4-56,ping报文å‘é€çš„æ•°æ®å­—节数,å¯ä»¥è¦æ ¹æ®è¿è¥å•†è¿›è¡Œè°ƒæ•´")) + packetsize.datatype = "range(4, 56)" + packetsize.default = "56" + packetsize:depends("alive", "1") + packetsize:depends("alive", "2") + packetsize:depends("alive", "3") + packetsize:depends("alive", "4") + +down = di:taboption(this_tab, ListValue, "down", translate("é“¾è·¯çŠ¶æ€ å¼‚å¸¸åˆ¤å®šæ¬¡æ•° :"), + translate("如果达到设定值次数,Ping便—§å¤±è´¥åŽï¼ŒæŽ¥å£å°±ä¼šè¢«å½“åšå¼‚常ä¸åœ¨çº¿")) +down.default = "3" +down:value("1") +down:value("2") +down:value("3") +down:value("4") +down:value("5") +down:value("6") +down:value("7") +down:value("8") +down:value("9") +down:value("10") +down:depends("alive", "1") +down:depends("alive", "2") +down:depends("alive", "3") +down:depends("alive", "4") + +up = di:taboption(this_tab, ListValue, "up", translate("é“¾è·¯çŠ¶æ€ æ­£å¸¸åˆ¤å®šæ¬¡æ•° :"), + translate("Tips:当达到设定值次数Ping监测åŽï¼Œç½‘络都能Ping设定地å€åŽï¼Œåˆ™é“¾è·¯çжæ€ä¼šè¢«è§†ä¸ºæ­£å¸¸å•¦~~")) +up.default = "3" +up:value("1") +up:value("2") +up:value("3") +up:value("4") +up:value("5") +up:value("6") +up:value("7") +up:value("8") +up:value("9") +up:value("10") +up:depends("alive", "1") +up:depends("alive", "2") +up:depends("alive", "3") +up:depends("alive", "4") + +cb2 = di:taboption(this_tab, DynamicList, "trackip", translate("追踪 IP :"), + translate("这个IP将被拿æ¥åšé“¾è·¯çŠ¶æ€æ£€æµ‹ç”¨ï¼Œç®€å•说就是Ping它,能通那么就算链路正常,ä¸é€šé‚£å°±ä»¥ä½ åˆšé…åˆçš„æ–¹æ³•处ç†")) +cb2.datatype = "ipaddr" +cb2:depends("alive", "1") +cb2:depends("alive", "2") +cb2:depends("alive", "3") +cb2:depends("alive", "4") +cb2.optional=false; +cb2.default="114.114.114.114" + +if (multilock == "0") or (multilock == "1" and rootlock == "1") then + this_tab = "bwidth" + bwday = di:taboption(this_tab, ListValue, "bwday", translate("å‘é€ç›‘测信æ¯çš„æ—¥æœŸ :"), + translate("æ¯æœˆå‘é€ç›‘测报告文件的日期,请选择在æ¯ä¸ªæœˆçš„第几日å‘é€ï¼Œä¸éœ€è¦è¯·é€‰æ‹©ç¦ç”¨")) + bwday.default = "0" + bwday:value("0", translate("ç¦ç”¨")) + bwday:value("1", translate("1æ—¥")) + bwday:value("2", translate("2æ—¥")) + bwday:value("3", translate("3æ—¥")) + bwday:value("4", translate("4æ—¥")) + bwday:value("5", translate("5æ—¥")) + bwday:value("6", translate("6æ—¥")) + bwday:value("7", translate("7æ—¥")) + bwday:value("8", translate("8æ—¥")) + bwday:value("9", translate("9æ—¥")) + bwday:value("10", translate("10æ—¥")) + bwday:value("11", translate("11æ—¥")) + bwday:value("12", translate("12æ—¥")) + bwday:value("13", translate("13æ—¥")) + bwday:value("14", translate("14æ—¥")) + bwday:value("15", translate("15æ—¥")) + bwday:value("16", translate("16æ—¥")) + bwday:value("17", translate("17æ—¥")) + bwday:value("18", translate("18æ—¥")) + bwday:value("19", translate("19æ—¥")) + bwday:value("20", translate("20æ—¥")) + bwday:value("21", translate("21æ—¥")) + bwday:value("22", translate("22æ—¥")) + bwday:value("23", translate("23æ—¥")) + bwday:value("24", translate("24æ—¥")) + bwday:value("25", translate("25æ—¥")) + bwday:value("26", translate("26æ—¥")) + bwday:value("27", translate("27æ—¥")) + bwday:value("28", translate("28æ—¥")) + + phone = di:taboption(this_tab, Value, "phone", translate("手机å·ç  :"), translate("我们将会通过这个手机å·ç ç»™ä½ å‘é€ç›‘测日志报告,物è”å¡å°±çˆ¬å§å‘ä¸äº†çš„,短信费用按你套é¤èµ„费扣,介æ„就别è¸é©¬ç”¨äº†")) + phone.default = "填入接收监测报告的手机å·ç ï¼Œæˆ‘们将会以短信方å¼ç»™ä½ å‘é€" + + bwdelay = di:taboption(this_tab, ListValue, "bwdelay", translate("å‘é€å‰å»¶è¿Ÿ :"), + translate("凌晨åŽå‡ ä¸ªå°æ—¶å‘é€çŸ­ä¿¡ç»™ä½ ")) + bwdelay:value("0", translate("ä¸å»¶è¿Ÿ")) + bwdelay:value("1", translate("1 å°æ—¶")) + bwdelay:value("2", translate("2 å°æ—¶")) + bwdelay:value("3", translate("3 å°æ—¶")) + bwdelay:value("4", translate("4 å°æ—¶")) + bwdelay:value("5", translate("5 å°æ—¶")) + bwdelay:value("6", translate("6 å°æ—¶")) + bwdelay:value("7", translate("7 å°æ—¶")) + bwdelay:value("8", translate("8 å°æ—¶")) + bwdelay:value("9", translate("9 å°æ—¶")) + bwdelay:value("10", translate("10 å°æ—¶")) + bwdelay:value("11", translate("11 å°æ—¶")) + bwdelay:value("12", translate("12 å°æ—¶")) +end + +if fs.stat("/usr/lib/autoapn/apn.data") then + dda = m:section(TypedSection, "disable", translate("Use Automatic APN"), translate("Enable the use of the Automatic APN selection. This disables Custom Profiles.")) + dda.anonymous = true + aenabled = dda:option(Flag, "autoapn", translate("Enabled")) + aenabled.default="0" + aenabled.optional=false; +end + +dd = m:section(TypedSection, "disable", translate("ç¦ç”¨è‡ªåЍAPN :"), translate("ç¦ç”¨è‡ªåЍAPNåŽï¼Œæ‰€æœ‰4G/5G通信模å—将会使用默认é…置文件,ä¸å‹¾é€‰å°±æ˜¯é»˜è®¤å¯ç”¨")) +dd.anonymous = true + +enabled = dd:option(Flag, "enabled", translate("ç¦ç”¨")) +enabled.default="0" +enabled.optional=false; + +-- +-- Custom profile +-- + +s = m:section(TypedSection, "custom", translate("定制特定组åˆé…ç½® :"), translate("å¯å°†æŸä¸ªç‰¹å®šé…置应用在你所选中的4G/5G模å—与SIMå¡ç»„åˆä¸­")) +s.anonymous = true +s.addremove = true +s:tab("custom", translate("简è¦")) +s:tab("cadvanced", translate("高级")) +s:tab("cconnect", translate("网络异常自动处ç†")) +if (multilock == "0") or (multilock == "1" and rootlock == "1") then + s:tab("cbwidth", translate("通信模å—频宽日志")) +end + +this_ctab = "custom" + +name = s:taboption(this_ctab, Value, "name", translate("é…ç½®åç§° :")) + +enabled = s:taboption(this_ctab, Flag, "enabled", translate("å¯ç”¨")) +enabled.default="1" +enabled.optional=false; + +select = s:taboption(this_ctab, ListValue, "select", translate("选择对象 :")); +select:value("0", translate("æ¨¡å— ID")) +select:value("1", translate("æ¨¡å— IMEI")) +select:value("2", translate("模å—åç§°")) +select:value("3", translate("SIMå¡IMSI")) +select:value("4", translate("SIMå¡ICCID")) +select.default=0 + +idV = s:taboption(this_ctab, Value, "vid", translate("USB VID :")); +idV.optional=false; +idV:depends("select", "0") +idV.default="xxxx" + +idP = s:taboption(this_ctab, Value, "pid", translate("USB PID :")); +idP.optional=false; +idP:depends("select", "0") +idP.default="xxxx" + +imei = s:taboption(this_ctab, Value, "imei", translate("通信模å—IMEI :")); +imei.optional=false; +imei:depends("select", "1") +imei.datatype = "uinteger" +imei.default="1234567" + +model = s:taboption(this_ctab, Value, "model", translate("模å—åç§°åŒ…å« :")); +model.optional=false; +model:depends("select", "2") +model.default="xxxx" + +imsi = s:taboption(this_ctab, Value, "imsi", translate("SIMå¡IMSI :")); +imsi.optional=false; +imsi:depends("select", "3") +imsi.datatype = "uinteger" +imsi.default="1234567" + +iccid = s:taboption(this_ctab, Value, "iccid", translate("SIMå¡ICCID :")); +iccid.optional=false; +iccid:depends("select", "4") +iccid.datatype = "uinteger" +iccid.default="1234567" + +select1 = s:taboption(this_ctab, ListValue, "select1", translate("选择组åˆå¯¹è±¡ :")); +select1:value("0", "æ¨¡å— ID") +select1:value("1", "æ¨¡å— IMEI") +select1:value("2", "åž‹å·åç§°") +select1:value("3", "SIMå¡IMSI") +select1:value("4", "SIMå¡ICCID") +select1:value("10", "None") +select1.default=10 + +idV1 = s:taboption(this_ctab, Value, "vid1", translate("USB VID :")); +idV1.optional=false; +idV1:depends("select1", "0") +idV1.default="xxxx" + +idP1 = s:taboption(this_ctab, Value, "pid1", translate("USB PID :")); +idP1.optional=false; +idP1:depends("select1", "0") +idP1.default="xxxx" + +imei1 = s:taboption(this_ctab, Value, "imei1", translate("æ¨¡å— IMEI :")); +imei1.optional=false; +imei1:depends("select1", "1") +imei1.datatype = "uinteger" +imei1.default="1234567" + +model1 = s:taboption(this_ctab, Value, "model1", translate("æ¨¡å— åç§°åŒ…å« :")); +model1.optional=false; +model1:depends("select1", "2") +model1.default="xxxx" + +imsi1 = s:taboption(this_ctab, Value, "imsi1", translate("SIMå¡IMSI :")); +imsi1.optional=false; +imsi1:depends("select1", "3") +imsi1.datatype = "uinteger" +imsi1.default="1234567" + +iccid1 = s:taboption(this_ctab, Value, "iccid1", translate("SIMå¡ICCID :")); +iccid1.optional=false; +iccid1:depends("select1", "4") +iccid1.datatype = "uinteger" +iccid1.default="1234567" + +cma = s:taboption(this_ctab, Value, "apn", "APN :"); +cma.rmempty = true; + +tt = s:taboption(this_ctab, ListValue, "ttl", translate("自定义TTL值 :")) +tt:value("0", translate("Use Current Value")) +tt:value("1", translate("No TTL Value")) +tt:value("63", "TTL 63") +tt:value("64", "TTL 64") +tt:value("65", "TTL 65") +tt:value("66", "TTL 66") +tt:value("67", "TTL 67") +tt:value("117", "TTL 117") +tt:value("TTL-INC 1", "TTL-INC 1") +tt.default = "0" + +nl = s:taboption(this_ctab, ListValue, "hostless", translate("调整无主机(无主控)模å—çš„TTL值 :")); +nl:value("0", translate("No")) +nl:value("1", translate("是")) +nl.default=0 + +pt = s:taboption(this_ctab, ListValue, "pdptype", translate("IPå议类型 :")) +pt:value("IP", "IPv4") +pt:value("IPv6", "IPv6") +pt:value("IPV4V6", "IPv4+IPv6") +pt:value("0", "Default") +pt.default = "0" + +cmcc = s:taboption(this_ctab, Value, "context", translate("PDP Context for APN :")); +cmcc.optional=false; +cmcc.rmempty = true; +cmcc.datatype = "and(uinteger,min(1),max(10))" +cmcc.default = "1" + +cmu = s:taboption(this_ctab, Value, "user", translate("用户å :")); +cmu.optional=false; +cmu.rmempty = true; + +cmp = s:taboption(this_ctab, Value, "passw", translate("å¯†ç  :")); +cmp.optional=false; +cmp.rmempty = true; +cmp.password = true + +cmpi = s:taboption(this_ctab, Value, "pincode", "PINç  :"); +cmpi.optional=false; +cmpi.rmempty = true; + +cmau = s:taboption(this_ctab, ListValue, "auth", translate("身份验è¯ç±»åž‹ :")) +cmau:value("0", "æ— ") +cmau:value("1", "PAP") +cmau:value("2", "CHAP") +cmau.default = "0" + +cmtz = s:taboption(this_ctab, ListValue, "tzone", translate("自动设置时区"), translate("模å—通网åŽè‡ªåŠ¨è®¾ç½®æ—¶åŒº")); +cmtz:value("0", translate("ç¦ç”¨")) +cmtz:value("1", translate("å¯ç”¨")) +cmtz.default=1 + +cml = s:taboption(this_ctab, ListValue, "lock", translate("是å¦é”定国际漫游è¿è¥å•†é€‰é¡¹(国内ä¸ç”¨ç®¡) :")); +cml:value("0", translate("å¦")) +cml:value("1", translate("强硬的")) +cml:value("2", translate("柔弱的")) +cml.default=0 + +cmcc = s:taboption(this_ctab, Value, "mcc", translate("MCC :")); +cmcc.optional=false; +cmcc.rmempty = true; +cmcc.datatype = "and(uinteger,min(1),max(999))" +cmcc:depends("lock", "1") +cmcc:depends("lock", "2") + +cmnc = s:taboption(this_ctab, Value, "mnc", translate("MNC :")); +cmnc.optional=false; +cmnc.rmempty = true; +cmnc.datatype = "and(uinteger,min(1),max(999))" +cmnc:depends("lock", "1") +cmnc:depends("lock", "2") + +this_ctaba = "cadvanced" + +cmf = s:taboption(this_ctaba, ListValue, "ppp", translate("强制使用3G PPåè®®æ‹¨å· :")); +cmf:value("0", translate("å¦")) +cmf:value("1", translate("是")) +cmf.default=0 + +cmw = s:taboption(this_ctaba, ListValue, "inter", translate("模å—WANå£åˆ†é… :")); +cmw:value("0", "自动") +cmw:value("1", "WAN1") +cmw:value("2", "WAN2") +cmw:value("3", "关闭") +cmw.default=0 + +cmd = s:taboption(this_ctaba, Value, "delay", translate("连接延迟(以秒为å•ä½) :")); +cmd.optional=false; +cmd.rmempty = false; +cmd.default = 5 +cmd.datatype = "and(uinteger,min(5))" + +cnl = s:taboption(this_ctaba, ListValue, "nodhcp", translate("强制QMIåè®®ä¸ä½¿ç”¨æ¨¡å—çš„DHCP,从其他ä½ç½®èŽ·å– :")); +cnl:value("0", translate("ç¦ç”¨")) +cnl:value("1", translate("å¯ç”¨")) +cnl.default=0 + +cmdns1 = s:taboption(this_ctaba, Value, "dns1", translate("自定义1 :")); +cmdns1.rmempty = true; +cmdns1.optional=false; +cmdns1.datatype = "ipaddr" + +cmdns2 = s:taboption(this_ctaba, Value, "dns2", translate("自定义2 :")); +cmdns2.rmempty = true; +cmdns2.optional=false; +cmdns2.datatype = "ipaddr" + +cmdns3 = s:taboption(this_ctaba, Value, "dns3", translate("自定义3 :")); +cmdns3.rmempty = true; +cmdns3.optional=false; +cmdns3.datatype = "ipaddr" + +cmdns4 = s:taboption(this_ctaba, Value, "dns4", translate("自定义4 :")); +cmdns4.rmempty = true; +cmdns4.optional=false; +cmdns4.datatype = "ipaddr" + +cmlog = s:taboption(this_ctaba, ListValue, "log", translate("å¯ç”¨è¿žæŽ¥æ—¥å¿— :")); +cmlog:value("0", translate("ç¦ç”¨")) +cmlog:value("1", translate("å¯ç”¨")) +cmlog.default=0 + +if nixio.fs.access("/etc/config/mwan3") then + cmlb = s:taboption(this_ctaba, ListValue, "lb", translate("在多个5G模å—䏭开坿µé‡è´Ÿè½½å‡è¡¡ :")); + cmlb:value("0", translate("ç¦ç”¨")) + cmlb:value("1", translate("å¯ç”¨")) + cmlb.default=0 +end + +mtu = s:taboption(this_ctaba, Value, "mtu", translate("自定义MTU值 :"), + translate("歪歪歪 米乱整çªï¼Œçº¸èƒ½è‡ªå®šä¹‰1420到1500的蜗 æ ¹æ®ä¸åŒè¿è¥å•†è¿›è¡Œè°ƒæ•´çš„æ­ªï¼Œç†ä¸é¸¡ä¸¢å°±ä¸è¦çžŽæžäº†è›™ï¼Œç­‰å¤åˆ—ä¸ªç½‘ç‚¸å˜¿æŽ‰äº†é³–å˜¿æ¥æ‰¾æˆ‘蜗~~")); +mtu.optional=true +mtu.rmempty = true +mtu.default = "1500" +mtu.datatype = "range(1420, 1500)" + +cmat = s:taboption(this_ctaba, ListValue, "at", translate("åœ¨è¿žæŽ¥æ¨¡å—æ—¶å‘é€è‡ªå®šä¹‰AT命令 :")); +cmat:value("0", translate("ç¦ç”¨")) +cmat:value("1", translate("å¯ç”¨")) +cmat.default=0 + +cmatc = s:taboption(this_ctaba, Value, "atc", translate("自定义AT命令 :")); +cmatc.optional=false; +cmatc.rmempty = true; + +-- +-- Custom Connection Monitoring +-- + +this_ctab = "cconnect" + +calive = s:taboption(this_ctab, ListValue, "alive", translate("连接状æ€ç›‘控 :")); +calive.rmempty = true; +calive:value("0", translate("ç¦ç”¨")) +calive:value("1", translate("å¯ç”¨æŽ‰çº¿å†™å…¥ç³»ç»Ÿæ—¥å¿—")) +calive:value("2", translate("å¯ç”¨ 5Gæ¨¡å—æŽ‰çº¿ 则 路由自动é‡å¯")) +calive:value("3", translate("å¯ç”¨ 5Gæ¨¡å—æŽ‰çº¿ 则 è‡ªåŠ¨é‡æ‹¨")) +calive:value("4", translate("å¯ç”¨ 5Gæ¨¡å—æŽ‰çº¿ 则 釿–°ä¸Šç”µæ¨¡å—,需è¦è·¯ç”±GPIO支æŒï¼Œå¦åˆ™å°†ä½¿ç”¨å…¶ä»–æ–¹å¼é‡è¿ž")) +calive.default=0 + +reliability = s:taboption(this_ctab, Value, "reliability", translate("监测网络稳定性 :"), + translate("Acceptable values: 范围: 1-100,必须Ping通这些IP地å€ï¼Œè¿™æ¡é€šä¿¡é“¾è·¯æ‰ä¼šè¢«è§†ä¸ºè”网状æ€")) +reliability.datatype = "range(1, 100)" +reliability.default = "1" +reliability:depends("alive", "1") +reliability:depends("alive", "2") +reliability:depends("alive", "3") +reliability:depends("alive", "4") + +count = s:taboption(this_ctab, ListValue, "count", translate("监测次数(Ping):")) +count.default = "1" +count:value("1") +count:value("2") +count:value("3") +count:value("4") +count:value("5") +count:depends("alive", "1") +count:depends("alive", "2") +count:depends("alive", "3") +count:depends("alive", "4") + +interval = s:taboption(this_ctab, ListValue, "pingtime", translate("监测时间间隔 (Ping) :"), + translate("监测Ping之间间隔时间的值")) +interval.default = "10" +interval:value("5", translate("5 ç§’")) +interval:value("10", translate("10 ç§’")) +interval:value("20", translate("20 ç§’")) +interval:value("30", translate("30 ç§’")) +interval:value("60", translate("1 分钟")) +interval:value("300", translate("5 分钟")) +interval:value("600", translate("10 分钟")) +interval:value("900", translate("15 分钟")) +interval:value("1800", translate("30 分钟")) +interval:value("3600", translate("1 å°æ—¶")) +interval:depends("alive", "1") +interval:depends("alive", "2") +interval:depends("alive", "3") +interval:depends("alive", "4") + +timeout = s:taboption(this_ctab, ListValue, "pingwait", translate("Ping è¶…æ—¶ :")) +timeout.default = "2" +timeout:value("1", translate("1 ç§’")) +timeout:value("2", translate("2 ç§’")) +timeout:value("3", translate("3 ç§’")) +timeout:value("4", translate("4 ç§’")) +timeout:value("5", translate("5 ç§’")) +timeout:value("6", translate("6 ç§’")) +timeout:value("7", translate("7 ç§’")) +timeout:value("8", translate("8 ç§’")) +timeout:value("9", translate("9 ç§’")) +timeout:value("10", translate("10 ç§’")) +timeout:depends("alive", "1") +timeout:depends("alive", "2") +timeout:depends("alive", "3") +timeout:depends("alive", "4") + +packetsize = s:taboption(this_ctab, Value, "packetsize", translate("Ping报文大å°(字节为å•ä½) :"), + translate("范围值 :4-56,ping报文å‘é€çš„æ•°æ®å­—节数,å¯ä»¥è¦æ ¹æ®è¿è¥å•†è¿›è¡Œè°ƒæ•´")) + packetsize.datatype = "range(4, 56)" + packetsize.default = "56" + packetsize:depends("alive", "1") + packetsize:depends("alive", "2") + packetsize:depends("alive", "3") + packetsize:depends("alive", "4") + +down = s:taboption(this_ctab, ListValue, "down", translate("é“¾è·¯çŠ¶æ€ å¼‚å¸¸åˆ¤å®šæ¬¡æ•° :"), + translate("如果达到设定值次数,Ping便—§å¤±è´¥åŽï¼ŒæŽ¥å£å°±ä¼šè¢«å½“åšå¼‚常ä¸åœ¨çº¿")) +down.default = "3" +down:value("1") +down:value("2") +down:value("3") +down:value("4") +down:value("5") +down:value("6") +down:value("7") +down:value("8") +down:value("9") +down:value("10") +down:depends("alive", "1") +down:depends("alive", "2") +down:depends("alive", "3") +down:depends("alive", "4") + +up = s:taboption(this_ctab, ListValue, "up", translate("é“¾è·¯çŠ¶æ€ æ­£å¸¸åˆ¤å®šæ¬¡æ•°"), + translate("当达到设定值次数Ping监测åŽï¼Œç½‘络都能Ping设定地å€åŽï¼Œåˆ™é“¾è·¯çжæ€ä¼šè¢«è§†ä¸ºæ­£å¸¸å•¦~~")) +up.default = "3" +up:value("1") +up:value("2") +up:value("3") +up:value("4") +up:value("5") +up:value("6") +up:value("7") +up:value("8") +up:value("9") +up:value("10") +up:depends("alive", "1") +up:depends("alive", "2") +up:depends("alive", "3") +up:depends("alive", "4") + +cb2 = s:taboption(this_ctab, DynamicList, "trackip", translate("追踪 IP :"), + translate("这个IP将被拿æ¥åšé“¾è·¯çŠ¶æ€æ£€æµ‹ç”¨ï¼Œç®€å•说就是Ping它,能通那么就算链路正常,ä¸é€šé‚£å°±ä»¥ä½ åˆšé…åˆçš„æ–¹æ³•处ç†")) +cb2.datatype = "ipaddr" +cb2:depends("alive", "1") +cb2:depends("alive", "2") +cb2:depends("alive", "3") +cb2:depends("alive", "4") +cb2.optional=false; +cb2.default="114.114.114.114" + +if (multilock == "0") or (multilock == "1" and rootlock == "1") then + this_ctab = "cbwidth" + bwday = s:taboption(this_ctab, ListValue, "bwday", translate("æ¯ä¸ªæœˆå‘é€ç½‘络稳定日志的日期"), + translate("æ¯æœˆå‘é€ç›‘测报告文件的日期,请选择在æ¯ä¸ªæœˆçš„第几日å‘é€ï¼Œä¸éœ€è¦è¯·é€‰æ‹©ç¦ç”¨")) + bwday.default = "0" + bwday:value("0", translate("ç¦ç”¨")) + bwday:value("1", translate("1æ—¥")) + bwday:value("2", translate("2æ—¥")) + bwday:value("3", translate("3æ—¥")) + bwday:value("4", translate("4æ—¥")) + bwday:value("5", translate("5æ—¥")) + bwday:value("6", translate("6æ—¥")) + bwday:value("7", translate("7æ—¥")) + bwday:value("8", translate("8æ—¥")) + bwday:value("9", translate("9æ—¥")) + bwday:value("10", translate("10æ—¥")) + bwday:value("11", translate("11æ—¥")) + bwday:value("12", translate("12æ—¥")) + bwday:value("13", translate("13æ—¥")) + bwday:value("14", translate("14æ—¥")) + bwday:value("15", translate("15æ—¥")) + bwday:value("16", translate("16æ—¥")) + bwday:value("17", translate("17æ—¥")) + bwday:value("18", translate("18æ—¥")) + bwday:value("19", translate("19æ—¥")) + bwday:value("20", translate("20æ—¥")) + bwday:value("21", translate("21æ—¥")) + bwday:value("22", translate("22æ—¥")) + bwday:value("23", translate("23æ—¥")) + bwday:value("24", translate("24æ—¥")) + bwday:value("25", translate("25æ—¥")) + bwday:value("26", translate("26æ—¥")) + bwday:value("27", translate("27æ—¥")) + bwday:value("28", translate("28æ—¥")) + + phone = s:taboption(this_ctab, Value, "phone", translate("手机å·ç  :"), translate("我们将会通过这个手机å·ç ç»™ä½ å‘é€ç›‘测日志报告,物è”å¡å°±çˆ¬å§å‘ä¸äº†çš„,短信费用按你套é¤èµ„费扣,介æ„å°±ä¸è¦ç”¨äº†")) + phone.default = "12223334444" + + bwdelay = s:taboption(this_ctab, ListValue, "bwdelay", translate("å‘é€å‰å»¶è¿Ÿ :"), + translate("凌晨åŽå‡ ä¸ªå°æ—¶å‘é€çŸ­ä¿¡ç»™ä½ ")) + bwdelay:value("0", translate("No Delay")) + bwdelay:value("1", translate("1 å°æ—¶")) + bwdelay:value("2", translate("2 å°æ—¶")) + bwdelay:value("3", translate("3 å°æ—¶")) + bwdelay:value("4", translate("4 å°æ—¶")) + bwdelay:value("5", translate("5 å°æ—¶")) + bwdelay:value("6", translate("6 å°æ—¶")) + bwdelay:value("7", translate("7 å°æ—¶")) + bwdelay:value("8", translate("8 å°æ—¶")) + bwdelay:value("9", translate("9 å°æ—¶")) + bwdelay:value("10", translate("10 å°æ—¶")) + bwdelay:value("11", translate("11 å°æ—¶")) + bwdelay:value("12", translate("12 å°æ—¶")) +end + +return m + + + diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/admin_status/index/external.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/admin_status/index/external.htm new file mode 100644 index 0000000..9aa6023 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/admin_status/index/external.htm @@ -0,0 +1 @@ +<%+rooter/external%> \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/admin_system/poweroff.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/admin_system/poweroff.htm new file mode 100644 index 0000000..4749e48 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/admin_system/poweroff.htm @@ -0,0 +1,34 @@ +<%# + Copyright 2008 Steven Barth + Copyright 2008 Jo-Philipp Wich + Licensed to the public under the Apache License 2.0. +-%> + +<%+header%> + + + + +

                          <%:System%>

                          +

                          <%:System Stop%>

                          +

                          <%:Graceful system stop. De-power then re-power to restart.%>

                          +

                          +
                            +<%+footer%> \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/modlog/modlog.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/modlog/modlog.htm new file mode 100644 index 0000000..edf4af4 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/modlog/modlog.htm @@ -0,0 +1,32 @@ +<%+header%> + + + + +
                            +

                            <%:Modem Logging%>

                            +
                            +
                            + <%:Log%> + + + + +
                            + +
                            + +
                            + +
                            + +<%+footer%> \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/bandlock.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/bandlock.htm new file mode 100644 index 0000000..3dd5477 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/bandlock.htm @@ -0,0 +1,26 @@ +<%+header%> + + + + +
                            +
                            +

                            Band Locking Tutorial

                            +
                            Manually band lock a modem
                            +
                            + Versions + + + + + + +
                            Current Firmware :
                               
                              + +
                              +
                              +
                              +<%+footer%> \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/custom.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/custom.htm new file mode 100644 index 0000000..e23d1e8 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/custom.htm @@ -0,0 +1,126 @@ +<% +local modemfile = "/etc/config/modem.data" +local modemdata = {} +local count + +function process_line(xline, cnt) + local data = {} + local pline = xline + local start = 1 + for i=1,3 do + s, e = string.find(pline, " ") + data[i] = string.sub(pline, start, s-1) + pline = string.sub(pline, e+1) + end + data[4] = pline + modemdata[cnt] = data +end + +function read_modem() + count = 0 + local file = io.open(modemfile, "r") + if file == nil then + return + end + repeat + local line = file:read("*line") + if line == nil then + break + end + if string.len(line) < 5 then + break + end + count = count + 1 + process_line(line, count) + until 1==0 + file:close() +end + +function process_family(index) + local t = { } + if count == 0 then + return t + end + local mdata = modemdata[index] + if mdata[1] ~= "nil" and mdata[2] ~= "nil" then + t[1] = mdata[1] .. ":" .. mdata[2] + if mdata[3] == "tty" then + t[2] = "default" + end + if mdata[3] == "tty0" then + t[2] = "ttyUSB0" + end + if mdata[3] == "tty1" then + t[2] = "ttyUSB1" + end + if mdata[3] == "tty2" then + t[2] = "ttyUSB2" + end + if mdata[3] == "tty3" then + t[2] = "ttyUSB3" + end + if mdata[3] == "tty4" then + t[2] = "ttyUSB4" + end + if mdata[3] == "tty5" then + t[2] = "ttyUSB5" + end + + if mdata[4] == "tty" then + t[3] = "default" + end + if mdata[4] == "tty0" then + t[3] = "ttyUSB0" + end + if mdata[4] == "tty1" then + t[3] = "ttyUSB1" + end + if mdata[4] == "tty2" then + t[3] = "ttyUSB2" + end + if mdata[4] == "tty3" then + t[3] = "ttyUSB3" + end + if mdata[4] == "tty4" then + t[3] = "ttyUSB4" + end + if mdata[4] == "tty5" then + t[3] = "ttyUSB5" + end + + end + return t +end + +read_modem() + +%> + +
                              + <%:自定义模å—ç«¯å£æ•°æ®åº“%> + + + + + + + <% + if count > 0 then + for i=1,count do + t = process_family(i) %> + + + + + + <% + end + else %> + + + + <% + end %> +
                              <%:模å—åç§°%><%:æ•°æ®ç«¯å£%><%:通信端å£%>
                              <%=t[1]%><%=t[2]%><%=t[3]%>
                              <%:暂无数æ®%>  
                              +
                              + diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/debug.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/debug.htm new file mode 100644 index 0000000..e9f0d9c --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/debug.htm @@ -0,0 +1,87 @@ +<%+header%> + +<% +local cnt = 0 +local tt = {} + +os.execute("cat /sys/kernel/debug/usb/devices > /tmp/modstat 2>&1") +local file = io.open("/tmp/modstat", "r") +repeat + local line = file:read("*line") + if line == nil then + break + end + if string.len(line) < 3 then + line = "********************************************************************************************************" + end + tt[cnt] = line + cnt = cnt + 1 +until 1 == 0 +cnt = cnt - 1 +file:close() +os.execute("/usr/lib/rooter/luci/luaops.sh delete /tmp/modstat") +%> + + + + +
                              +

                              <%:通信模å—调试信æ¯%>

                              +
                              +
                              + <%:自动化AT指令调试日志%> + + + + +
                              + +
                              + +
                              + +
                              + <%:设备信æ¯%> + + + + + + + <% + for i=1,cnt do + s, e = string.find(tt[i], "供应商") + s1, e = string.find(tt[i], "å“牌") + s2, e = string.find(tt[i], "模å—åž‹å·") + if s ~= nil or s1 ~= nil or s2 ~= nil then + %> + + + + + + <% else + %> + + + + + + <% end + end %> +
                              <%=tt[i]%>
                              <%=tt[i]%>
                              +
                              +

                              +
                              + +<%+footer%> + diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/external.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/external.htm new file mode 100644 index 0000000..91927b7 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/external.htm @@ -0,0 +1,26 @@ + + +
                              +

                              <%:External Internet IP Address%>

                              + + +
                              <%:IP Address%><%:Loading%> Collecting data...
                              +
                              + diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/log.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/log.htm new file mode 100644 index 0000000..3928e06 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/log.htm @@ -0,0 +1,54 @@ +<%+header%> + + + + +
                              +
                              +

                              <%:连接日志%>

                              +
                              + +
                              + + + + + + + +
                              + +
                              + +
                              + +
                              + +
                              +
                              +<%+footer%> + diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/misc.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/misc.htm new file mode 100644 index 0000000..05a087e --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/misc.htm @@ -0,0 +1,2387 @@ +<%+header%> +<% +local sys = require "luci.sys" +local utl = require "luci.util" +local fs = require "nixio.fs" +local uci = require "luci.model.uci".cursor() +local s = uci:get("custom", "bandlock", "enabled") +local a = uci:get("custom", "atcmd", "enabled") + +local multilock = uci:get("custom", "multiuser", "multi") or "0" +local rootlock = uci:get("custom", "multiuser", "root") or "0" +nomulti=1 +if (multilock == "0") or (multilock == "1" and rootlock == "1") then + nosms = 1 + if a == "1" then + nosms = 0 + end +else + nosms = 1 + nomulti = 0 +end +block = 1 +if s == "1" then + block = 0 +end + +function showicon(lck) + if lck == 0 then + return resource .. "/icons/unlock1.png" + else + return resource .. "/icons/lock1.png" + end +end + +-%> + + + +
                              +
                              +

                              <%:é”频段/é”PCI/切æ¢åè®®/AT命令%>

                              +
                              <%:é”频段/é”PCI/切æ¢åè®®/AT命令%>
                              + + + +
                              + <%:当剿¨¡å—%> + + + + + + + +
                                + + + +
                                +
                                +
                                + <%:æ¨¡å— è¿žæŽ¥/断开控制%> + + + + + + + +
                                + + + + + + + +
                                +
                                + +<% if nosms == 0 then %> +
                                + <%:AT命令终端%> + + + + + + + + + + + + + + + +
                                <%:AT命令 : %>
                                + + + +  
                                +
                                + + + + + + + + + + + + + + + + + +
                                <%:AT命令 : %>
                                 
                                + + + + + +
                                + +
                                + +
                                +<% end %> + +<% if nomulti == 1 then %> +<% if block == 0 then %> +
                                + <%:4G/5G频段é”定%> + + + + + +
                                 
                                + + + + + + +
                                <%:没有模å—/æ¨¡å—æœªé€‚é…æœ¬æ’ä»¶%> 
                                + + + + + + + +
                                 
                                <%:4G LTE频段%>
                                 
                                + + + + +
                                + + + + + + + +
                                 
                                <%:5G NSA频段%>
                                 
                                + + + + +
                                + + + + + + + +
                                 
                                <%:5G SA 频段%>
                                 
                                + + + + +
                                + + + + + + + +
                                  
                                + + + + + +
                                 
                                + + + + + + +
                                 
                                + + + + + +
                                <%:2 x 载波èšåˆ%>
                                + + + + +
                                + + + + + +
                                <%:3 x 载波èšåˆ%>
                                + + + + +
                                + + + + + +
                                 
                                + + + + + + + + + +
                                 
                                <%:扫æå¯ç”¨çš„频段%>
                                 
                                + + + + + +
                                + +
                                + + + + + + + + + + +
                                  
                                <%:é”定基站%>
                                 
                                + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                <%:åŠŸèƒ½çŠ¶æ€ : %>
                                   
                                <%:EARFCN 1 : %>
                                <%:PCI 1 : %>
                                 
                                <%:EARFCN 2 : %>
                                <%:PCI 2 : %>
                                 
                                <%:EARFCN 3 : %>
                                <%:PCI 3 : %>
                                 
                                <%:EARFCN 4 : %>
                                <%:PCI 4 : %>
                                 
                                + + + + + + +
                                 
                                + +
                                +<% end %> + +
                                + <%:模å—连接å议切æ¢%> + + + + + + + + + + + + + +
                                 
                                <%:当剿¨¡å—连接åè®® :%>
                                 
                                 
                                <%:æ›´æ”¹èœ‚çªæ¨¡å¼ :%>
                                + + +
                                +
                                + +
                                + <%:网络类型选择%> + + + + + + + + + + + + + +
                                <%:当å‰ç½‘络类型 :%>
                                 
                                <%:更改网络类型 :%>
                                + + + + +  
                                +
                                +<% end %> + +
                                + <%:GPS Message Pin%> + + + + + + + + +
                                 
                                <%:Message Pin :%>
                                 
                                +
                                + +
                                +
                                +<%+footer%> diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/net_status.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/net_status.htm new file mode 100644 index 0000000..bcab6fa --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/net_status.htm @@ -0,0 +1,564 @@ +<%+header%> +<% +local fs = require "nixio.fs" +nosms = 1 +if not fs.stat("/etc/nosim") then + nosms = 0 +end +havegps = 0 +if fs.stat("/etc/havegps") then + havegps = 1 +end +-%> + + + + +
                                +
                                +

                                <%:ä¿¡å·çжæ€/模å—ä¿¡æ¯%>

                                +
                                请注æ„该æ’ä»¶æ‰€æœ‰åŠŸèƒ½å¹¶æ— é€‚é…æ‰€æœ‰5G模å—,ä¸ç”¨å¦„æƒ³å†·é—¨æ¨¡å—æ’上就能用(有能力者自行适é…) +
                                + + + +
                                + <%:综åˆä¿¡æ¯%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                <%:æ¨¡å— :%>
                                  + + + +
                                  <%:ID : %>
                                      
                                    <%:è¿è¥å•† : %>
                                        
                                      <%:ç«¯å£ :%>
                                        + + + +
                                        <%:温度 : %>
                                            
                                          <%:åè®® : %>
                                              
                                            +
                                            + +<% if nosms == 0 then %> +
                                            + <%:通信模å—/SIMå¡ä¿¡æ¯%> + + + + + + + + + + + + + + + + + + + + + + +
                                            + +    
                                            <%:IMEI:%>
                                                
                                              <%:IMSI:%>
                                                <%:ICCID:%>
                                                  + + + + + + + + + + + + +
                                                  <%:SIMå¡å·ç  : %>
                                                  + +   
                                                  <%:SIMå¡åç§° : %>
                                                  +
                                                  +<% end %> + +
                                                  + <%:ä¿¡å·çжæ€%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                  <%:蜂çªç½‘络类型 :%>
                                                     
                                                    <%:CSQ : %>
                                                       
                                                      <%:ä¿¡å·å¼ºåº¦ : %>
                                                         
                                                        <%:ä¿¡å·æŽ¥æ”¶å¼ºåº¦ RSSI : %>
                                                           
                                                          <%:å‚è€ƒä¿¡å·æŽ¥æ”¶è´¨é‡ RSRQ :%>
                                                           
                                                          <%:å‚è€ƒä¿¡å·æŽ¥æ”¶åŠŸçŽ‡ RSRP :%>
                                                           
                                                          <%:信噪比 SINR : %>
                                                             
                                                            <%:连接状æ€ç›‘控 : %>
                                                               
                                                              +
                                                              + +
                                                              + <%:基站信æ¯%> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                              <%:MCC / MNC :%>
                                                               
                                                              <%:eNB ID :%>
                                                               
                                                              <%:TAC :%>
                                                               
                                                              <%:Cell ID : %>
                                                               
                                                              <%:频段 Band : %>
                                                                 
                                                                <%:频点 Channel : %>
                                                                   
                                                                  <%:物ç†å°åŒºæ ‡è¯† PCI : %>
                                                                     
                                                                    <%:最大Qos级别 Maximum Qos : %>
                                                                     
                                                                    +
                                                                    + +<% if havegps == 1 then %> +
                                                                    + <%:GPS 定ä½%> + + + + + + + + + + + +
                                                                    <%:纬度 :%>
                                                                       
                                                                      <%:ç»åº¦ :%>
                                                                         
                                                                        +
                                                                        +<% end %> +
                                                                        + <%:刷新频率%> + + + + + + + + + + + + + +
                                                                        <%:当å‰åˆ·æ–°çއ :%>
                                                                         
                                                                        <%:修改刷新时间 :%>
                                                                        + +  
                                                                        +
                                                                        + +
                                                                        +
                                                                        +<%+footer%> + diff --git a/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/profile.htm b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/profile.htm new file mode 100644 index 0000000..64efa21 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/lua/luci/view/rooter/profile.htm @@ -0,0 +1,75 @@ +<% + +%> + + + +
                                                                        + <%:Import/Export the Profile Data%> + + + + + + + + + + + + + + + + +
                                                                         
                                                                        <%:Export Profile Data to Computer%>
                                                                         
                                                                        <%:Import Profile Data from Computer%>
                                                                          
                                                                        <%:Page will automatically refresh after file is loaded%>
                                                                        + +
                                                                        diff --git a/rooter/ext-rooter-basic/files/usr/lib/modlog/modlogger.sh b/rooter/ext-rooter-basic/files/usr/lib/modlog/modlogger.sh new file mode 100644 index 0000000..4c3a531 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/modlog/modlogger.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +TEXT=$1 +DATE=$(date +%c) + +modlog="/tmp/modlog.log" +tmplog="/tmp/tmodlog" + +wc -l $modlog > /tmp/linecnt +read lcnt fle < /tmp/linecnt +rm -f /tmp/linecnt +if [ $lcnt -ge 200 ]; then + start=$((lcnt-1)) + tail +$start modlog > $tmplog + mv $tmplog $modlog +fi + +echo "$DATE : $TEXT" >> $modlog diff --git a/rooter/ext-rooter-basic/files/usr/lib/profile/loadcfg.sh b/rooter/ext-rooter-basic/files/usr/lib/profile/loadcfg.sh new file mode 100644 index 0000000..09648f2 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/profile/loadcfg.sh @@ -0,0 +1,14 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Load" "$@" +} + +profile=$(cat /tmp/profilename) +valid=$(echo "$profile" | grep "**Profile**") +if [ ! -z "$valid" ]; then + echo "$profile" > /tmp/profile + sed -i '1d' /tmp/profile + cp /tmp/profile /etc/config/profile +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/profile/restart.sh b/rooter/ext-rooter-basic/files/usr/lib/profile/restart.sh new file mode 100644 index 0000000..cda742a --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/profile/restart.sh @@ -0,0 +1,18 @@ +#!/bin/sh +. /lib/functions.sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Restart" "$@" +} + +sleep 3 + +CURRMODEM=1 +CPORT=$(uci -q get modem.modem$CURRMODEM.commport) + +if [ ! -z $CPORT ]; then + ATCMDD="AT+CFUN=1,1" + $ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD" +fi \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/profile/savecfg.sh b/rooter/ext-rooter-basic/files/usr/lib/profile/savecfg.sh new file mode 100644 index 0000000..ab8c026 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/profile/savecfg.sh @@ -0,0 +1,16 @@ +#!/bin/sh +. /lib/functions.sh + +log() { + logger -t "Save" "$@" +} + +PKI_DIR="/www" +cd ${PKI_DIR} +mkdir -p package +cd .. +chmod -R 0777 ${PKI_DIR}/package + +echo "***Profile***" > ${PKI_DIR}/package/profilecfg.profile +state=$(cat /etc/config/profile) +echo "$state" >> ${PKI_DIR}/package/profilecfg.profile \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/autoapn.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/autoapn.sh new file mode 100644 index 0000000..c461f46 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/autoapn.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "SimLock " "$@" +} diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/cdmafind.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/cdmafind.lua new file mode 100644 index 0000000..b1f9922 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/cdmafind.lua @@ -0,0 +1,55 @@ +#!/usr/bin/lua + +drv = {} +idV = arg[1] +idP = arg[2] + +retval = 0 + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +-- MAIN + +local i=0 +local file = io.open("/tmp/cdma", "r") +repeat + local line = file:read("*line") + if line == nil then + break + end + if string.len(line) > 5 then + s, e = line:find("Vendor=") + if s ~= nil then + cs, ce = line:find(" ", e) + m_idV = trim(line:sub(e+1, cs-1)) + s, e = line:find("ProdID=") + cs, ce = line:find(" ", e) + m_idP = trim(line:sub(e+1, cs-1)) + if m_idV == idV and m_idP == idP then + repeat + line = file:read("*line") + if line == nil then + break + end + if string.len(line) > 5 then + s, e = line:find("Product=") + if s ~= nil then + s, e = line:find(" CDMA") + if s ~= nil then + retval = 1 + break + end + end + end + until 1==0 + break + end + end + end +until 1==0 +file:close() + + +os.exit(retval) \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/chan2band.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/chan2band.sh new file mode 100644 index 0000000..99b1ce3 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/chan2band.sh @@ -0,0 +1,273 @@ +#!/bin/sh +CHAN=$1 +CHAN=$(echo "$CHAN" | grep -o "[0-9]*") + +decode_lte() { + if [ $CHAN -lt 600 ]; then + BAND="B1" + elif [ $CHAN -lt 1200 ]; then + BAND="B2" + elif [ $CHAN -lt 1950 ]; then + BAND="B3" + elif [ $CHAN -lt 2400 ]; then + BAND="B4" + elif [ $CHAN -lt 2650 ]; then + BAND="B5" + elif [ $CHAN -lt 2750 ]; then + BAND="B6" + elif [ $CHAN -lt 3450 ]; then + BAND="B7" + elif [ $CHAN -lt 3800 ]; then + BAND="B8" + elif [ $CHAN -lt 4150 ]; then + BAND="B9" + elif [ $CHAN -lt 4750 ]; then + BAND="B10" + elif [ $CHAN -lt 4950 ]; then + BAND="B11" + elif [ $CHAN -lt 5010 ]; then + BAND="-" + elif [ $CHAN -lt 5180 ]; then + BAND="B12" + elif [ $CHAN -lt 5280 ]; then + BAND="B13" + elif [ $CHAN -lt 5380 ]; then + BAND="B14" + elif [ $CHAN -lt 5730 ]; then + BAND="-" + elif [ $CHAN -lt 5850 ]; then + BAND="B17" + elif [ $CHAN -lt 6000 ]; then + BAND="B18" + elif [ $CHAN -lt 6150 ]; then + BAND="B19" + elif [ $CHAN -lt 6450 ]; then + BAND="B20" + elif [ $CHAN -lt 6600 ]; then + BAND="B21" + elif [ $CHAN -lt 7400 ]; then + BAND="B22" + elif [ $CHAN -lt 7500 ]; then + BAND="-" + elif [ $CHAN -lt 7700 ]; then + BAND="B23" + elif [ $CHAN -lt 8040 ]; then + BAND="B24" + elif [ $CHAN -lt 8690 ]; then + BAND="B25" + elif [ $CHAN -lt 9040 ]; then + BAND="B26" + elif [ $CHAN -lt 9210 ]; then + BAND="B27" + elif [ $CHAN -lt 9660 ]; then + BAND="B28" + elif [ $CHAN -lt 9770 ]; then + BAND="B29" + elif [ $CHAN -lt 9870 ]; then + BAND="B30" + elif [ $CHAN -lt 9920 ]; then + BAND="B31" + elif [ $CHAN -lt 10400 ]; then + BAND="B32" + elif [ $CHAN -lt 36000 ]; then + BAND="-" + elif [ $CHAN -lt 36200 ]; then + BAND="B33" + elif [ $CHAN -lt 36350 ]; then + BAND="B34" + elif [ $CHAN -lt 36950 ]; then + BAND="B35" + elif [ $CHAN -lt 37550 ]; then + BAND="B36" + elif [ $CHAN -lt 37750 ]; then + BAND="B37" + elif [ $CHAN -lt 38250 ]; then + BAND="B38" + elif [ $CHAN -lt 38650 ]; then + BAND="B39" + elif [ $CHAN -lt 39650 ]; then + BAND="B40" + elif [ $CHAN -lt 41590 ]; then + BAND="B41" + elif [ $CHAN -lt 43590 ]; then + BAND="B42" + elif [ $CHAN -lt 45590 ]; then + BAND="B43" + elif [ $CHAN -lt 46590 ]; then + BAND="B44" + elif [ $CHAN -lt 46790 ]; then + BAND="B45" + elif [ $CHAN -lt 54540 ]; then + BAND="B46" + elif [ $CHAN -lt 55240 ]; then + BAND="B47" + elif [ $CHAN -lt 56740 ]; then + BAND="B48" + elif [ $CHAN -lt 58240 ]; then + BAND="B49" + elif [ $CHAN -lt 59090 ]; then + BAND="B50" + elif [ $CHAN -lt 59140 ]; then + BAND="B51" + elif [ $CHAN -lt 60140 ]; then + BAND="B52" + elif [ $CHAN -lt 60255 ]; then + BAND="B53" + elif [ $CHAN -lt 65536 ]; then + BAND="-" + elif [ $CHAN -lt 66436 ]; then + BAND="B65" + elif [ $CHAN -lt 67336 ]; then + BAND="B66" + elif [ $CHAN -lt 67536 ]; then + BAND="B67" + elif [ $CHAN -lt 67836 ]; then + BAND="B68" + elif [ $CHAN -lt 68336 ]; then + BAND="B69" + elif [ $CHAN -lt 68586 ]; then + BAND="B70" + elif [ $CHAN -lt 68936 ]; then + BAND="B71" + elif [ $CHAN -lt 68986 ]; then + BAND="B72" + elif [ $CHAN -lt 69036 ]; then + BAND="B73" + elif [ $CHAN -lt 69466 ]; then + BAND="B74" + elif [ $CHAN -lt 70316 ]; then + BAND="B75" + elif [ $CHAN -lt 70366 ]; then + BAND="B76" + elif [ $CHAN -lt 70546 ]; then + BAND="B85" + elif [ $CHAN -lt 70596 ]; then + BAND="B87" + elif [ $CHAN -lt 70646 ]; then + BAND="B88" + else + BAND="-" + fi +} + +decode_nr5g() { + if [ $CHAN -le 123400 ]; then + BAND="-" + elif [ $CHAN -le 130400 ]; then + BAND="n71" + elif [ $CHAN -le 143400 ]; then + BAND="-" + elif [ $CHAN -le 145600 ]; then + BAND="n29" + elif [ $CHAN -le 145800 ]; then + BAND="-" + elif [ $CHAN -le 149200 ]; then + BAND="n12" + elif [ $CHAN -le 151600 ]; then + BAND="-" + elif [ $CHAN -le 153600 ]; then + BAND="n14|n28" + elif [ $CHAN -le 158200 ]; then + BAND="n28" + elif [ $CHAN -le 160600 ]; then + BAND="n20|n28" + elif [ $CHAN -le 164200 ]; then + BAND="n20" + elif [ $CHAN -le 171800 ]; then + BAND="-" + elif [ $CHAN -le 172000 ]; then + BAND="n26" + elif [ $CHAN -le 173800 ]; then + BAND="n18|n26" + elif [ $CHAN -le 175000 ]; then + BAND="n5|n18|n26" + elif [ $CHAN -le 178800 ]; then + BAND="n5|n26" + elif [ $CHAN -le 185000 ]; then + BAND="-" + elif [ $CHAN -le 192000 ]; then + BAND="n8" + elif [ $CHAN -le 285400 ]; then + BAND="-" + elif [ $CHAN -le 286400 ]; then + BAND="n51|n76|n91|n93" + elif [ $CHAN -le 295000 ]; then + BAND="n50|n75|n92|n94" + elif [ $CHAN -le 303400 ]; then + BAND="n50|n74|n75|n92|n94" + elif [ $CHAN -le 303600 ]; then + BAND="n74" + elif [ $CHAN -le 361000 ]; then + BAND="-" + elif [ $CHAN -le 376000 ]; then + BAND="n3" + elif [ $CHAN -le 384000 ]; then + BAND="n39" + elif [ $CHAN -le 386000 ]; then + BAND="-" + elif [ $CHAN -le 398000 ]; then + BAND="n2|n25" + elif [ $CHAN -le 399000 ]; then + BAND="n25" + elif [ $CHAN -le 402000 ]; then + BAND="n70" + elif [ $CHAN -le 404000 ]; then + BAND="n34|n70" + elif [ $CHAN -le 405000 ]; then + BAND="n34" + elif [ $CHAN -le 422000 ]; then + BAND="-" + elif [ $CHAN -le 434000 ]; then + BAND="n1|n65|n66" + elif [ $CHAN -le 440000 ]; then + BAND="n65|n66" + elif [ $CHAN -le 460000 ]; then + BAND="-" + elif [ $CHAN -le 470000 ]; then + BAND="n40" + elif [ $CHAN -le 472000 ]; then + BAND="n30|n40" + elif [ $CHAN -le 480000 ]; then + BAND="n40" + elif [ $CHAN -le 496700 ]; then + BAND="-" + elif [ $CHAN -le 499000 ]; then + BAND="n53" + elif [ $CHAN -le 499200 ]; then + BAND="-" + elif [ $CHAN -le 514000 ]; then + BAND="n41|n90" + elif [ $CHAN -le 524000 ]; then + BAND="n38|n41|n90" + elif [ $CHAN -le 538000 ]; then + BAND="n7|n90" + elif [ $CHAN -le 620000 ]; then + BAND="-" + elif [ $CHAN -le 636667 ]; then + BAND="n77|n78" + elif [ $CHAN -le 646666 ]; then + BAND="n48|n77|n78" + elif [ $CHAN -le 653333 ]; then + BAND="n77|n78" + elif [ $CHAN -le 680000 ]; then + BAND="n77" + elif [ $CHAN -le 693334 ]; then + BAND="-" + elif [ $CHAN -le 733333 ]; then + BAND="n79" + else + BAND="-" + fi +} + +if [ -z "$CHAN" ]; then + BAND="-" +elif [ "$CHAN" -lt 123400 ]; then + decode_lte +elif [ "$CHAN" -lt 733333 ]; then + decode_nr5g +else + BAND="-" +fi +echo $BAND +exit diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/fibocomdata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/fibocomdata.sh new file mode 100644 index 0000000..8e4ef40 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/fibocomdata.sh @@ -0,0 +1,476 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Fibocom Data" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +decode_signal() { + if [ "$CRAT" -eq 4 ]; then + RSCPs=$(($RSRP - 141)) + if [ -n "$RSCP" ]; then + RSCP=$RSCP" dBm
                                                                        "$RSCPs + else + RSCP=$RSCPs + fi + if [ -n "$ECIO" ]; then + ECIO=$ECIO" dB
                                                                        "$((($RSRQ / 2) - 20)) + else + ECIO=$((($RSRQ / 2) - 20)) + fi + elif [ "$CRAT" -eq 9 ]; then + RSCPs=$(($RSRP - 157)) + if [ -n "$RSCP" ]; then + RSCP=$RSCP" dBm
                                                                        "$RSCPs + else + RSCP=$RSCPs + fi + if [ -n "$ECIO" ]; then + ECIO=$ECIO" dB
                                                                        "$((($RSRQ / 2) - 43)) + else + ECIO=$((($RSRQ / 2) - 43)) + fi + fi +} +decode_bw() { + case $BW in + "0") + BW="1.4" ;; + "1") + BW="3" ;; + "2") + BW="5" ;; + "3") + BW="10" ;; + "4") + BW="15" ;; + "5") + BW="20" ;; + *) + BW="-";; + esac +} + +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "fibocominfo.gcom" "$CURRMODEM") + +OX=$(echo $OX | tr 'a-z' 'A-Z') + +SERVING=$(echo $OX | grep -o "+GTCCINFO:.\+COPN:") +if [ -z "$SERVING" ]; then + SERVING=$(echo $OX | grep -o "+GTCCINFO:.\+GTRAT") +fi + +REGXa="[12],[249],[0-9]\{3\},[0-9]\{2,3\},[0-9A-F]\{0,5\},[0-9A-F]\{0,10\},[0-9A-F]\{1,8\},[0-9A-F]\{1,8\},[15][0-9]\{1,4\},[0-9]\{1,3\},[-0-9]\{1,5\},[0-9]\{1,3\},[0-9]\{1,3\},[0-9]\{1,3\}" + +REGXb="+GTCAINFO: 1,[0-9]\{1,2\},[0-9]\{3\},[0-9]\{2,3\},[0-9]\{1,5\},[0-9]\{3,9\},[0-9]\{1,3\},[0-9]\{1,3\},[0-9]\{1,3\},[-0-9]\{1,4\},[0-9]\{1,6\},[0-9]\{1,6\},[0-9]\{1,3\},[0-9]\{1,3\}" + +REGXc="+GTCAINFO: [2-9],[0-9]\{1,2\},[0-9]\{1,5\},[0-9]\{1,3\},[0-9]\{1,3\},[-0-9]\{1,4\},[0-9]\{1,5\},[0-9]\{1,5\},[0-9]\{1,3\},[0-9]\{1,3\}" + +REGXd="+XMCI: 2,[0-9]\{3\},[0-9]\{2,3\},[^,]\+,[^,]\+,[^,]\+,\"0X[0-9A-F]\{8\}\",[^,]\+,[^,]\+,[0-9]\{1,2\},[0-9]\{1,2\},[0-9]\{1,2\}" + +REGXe="+XMCI: 4,[0-9]\{3\},[0-9]\{2,3\},[^,]\+,[^,]\+,\"0X[0-9A-F]\{4\}\",\"0X[0-9A-F]\{8\}\",[^,]\+,[^,]\+,[0-9]\{1,2\},[0-9]\{1,2\},[-0-9]\{1,5\}" + +REGXf="SCC[0-9]: 1,0,[0-9]\{1,3\},1[0-9]\{2\},[0-9]\{1,6\},[0-9]\{1,3\}" + +REGXg="2,4,,,,,[0-9A-F]\{1,5\},[0-9A-F]\{1,3\},,[0-9]\{1,3\},[0-9]\{1,3\},[0-9]\{1,3\}" +REGXh="2,9,,,,,[0-9A-F]\{5\},[0-9A-F]\{1,3\},,[0-9]\{1,3\},[0-9]\{1,3\},[0-9]\{1,3\}" +REGXy="1,4,[0-9]\{3\},[0-9]\{2,3\},[0-9A-F]\{0,5\},[0-9A-F]\{0,10\},[0-9]\{1,8\}, ,[0-9]\{1,2\},[0-5], ," + +CHANNEL="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +NETMODE="-" +LBAND="-" +PCI="-" +CTEMP="-" +SINR="" +COPS_MCC="" + +CSQ=$(echo $OX | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") +if [ "$CSQ" = "99" ]; then + CSQ="" +fi +if [ -n "$CSQ" ]; then + CSQ_PER=$(($CSQ * 100/31))"%" + CSQ_RSSI=$((2 * CSQ - 113))" dBm" +else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" +fi + +if [ -n "$SERVING" ]; then + MODE=$(echo $SERVING | grep -o "+GTCCINFO: .\+ SERVICE CELL:") + LENM=${#MODE} + if [ $LENM -gt 25 ]; then + MODE=${MODE:11:$LENM-25} + else + MODE="-" + fi + GTCCDATA=$(echo $SERVING | grep -o "$REGXa") + GTCCDATAy=$(echo $SERVING | grep -o "$REGXy") + LTENEIGH=$(echo $SERVING | grep -o "$REGXg") + NRNEIGH=$(echo $SERVING | grep -o "$REGXh") + echo "" > /tmp/scan$CURRMODEM + for NVAL in $(echo "$LTENEIGH"); do + CHAN=$(echo $NVAL | cut -d, -f7) + CHAN=$(printf "%d" 0x$CHAN) + BAND=$(/usr/lib/rooter/chan2band.sh $CHAN) + PCIx=$(echo $NVAL | cut -d, -f8) + PCIx=$(printf "%d" 0x$PCIx) + RSSI=$(echo $NVAL | cut -d, -f11) + RSSI=$(($RSSI - 141)) + echo -e "Band : $BAND\tPCI : $PCIx\tSignal : $RSSI (dBm)" >> /tmp/scan$CURRMODEM + done + for NVAL in $(echo "$NRNEIGH"); do + CHAN=$(echo $NVAL | cut -d, -f7) + CHAN=$(printf "%d" 0x$CHAN) + BAND=$(/usr/lib/rooter/chan2band.sh $CHAN) + PCIx=$(echo $NVAL | cut -d, -f8) + PCIx=$(printf "%d" 0x$PCIx) + RSSI=$(echo $NVAL | cut -d, -f11) + RSSI=$(($RSSI - 157)) + echo -e "Band : $BAND\tPCI : $PCIx\tSignal : $RSSI (dBm)" >> /tmp/scan$CURRMODEM + done + CADATA1="" + CADATA2="" + XUDATA="" + XLDATA="" +else + GTCCDATA="" + CADATA1=$(echo $OX | grep -o "$REGXb") + CADATA2=$(echo $OX | grep -o "$REGXc") + if [ -n "$CADATA2" ]; then + if [ "$(echo $CADATA2 | cut -d, -f7)" = "65535" ]; then + CADATA2="" + fi + fi + XUDATA=$(echo $OX | grep -o "$REGXd") + XLDATA=$(echo $OX | grep -o "$REGXe") +fi +CADATA3=$(echo $OX | grep -o "$REGXf") +if [ -n "$GTCCDATA" ]; then + COPS_MCC=$(echo $GTCCDATA | cut -d, -f3) + COPS_MNC=$(echo $GTCCDATA | cut -d, -f4) + COPX="" + COPN=$(echo $OX" " | grep -o "+COPN: .\+ OK " | tr " " "," | tr -d '"' ) + if [ -n "$COPN" ]; then + COPP=$(echo $COPN" " | sed "s/.*\($COPS_MCC$COPS_MNC,.*\)\,/\1/") + if [ -n "$COPP" ]; then + COPX=$(echo $COPP | cut -d, -f2) + fi + fi + + LBAND="" + CHANNEL="" + RSCP="" + ECIO="" + PCI="" + XUDATA="" + for CCVAL in $(echo "$GTCCDATA"); do + CELLTYPE=$(echo $CCVAL | cut -d, -f1) + CRAT=$(echo $CCVAL | cut -d, -f2) + BAND=$(echo $CCVAL | cut -d, -f9) + CHAN=$(echo $CCVAL | cut -d, -f7) + CHAN=$(printf "%d" 0x$CHAN) + PCID=$(echo $CCVAL | cut -d, -f8) + PCID=$(printf "%d" 0x$PCID) + BW=$(echo $CCVAL | cut -d, -f10) + if [ "$CRAT" -eq 4 ]; then + SSINR=$(echo $CCVAL | cut -d, -f11 | grep -o "[-0-9]\{1,4\}") + if [ -n "$SSINR" ] && [ "$SSINR" != "255" ]; then + SSINR=$(($SSINR / 2))" dB" + else + SSINR="-" + fi + if [ -n "$SINR" ]; then + SINR=$SINR"
                                                                        "$SSINR + else + SINR=$SSINR + fi + if [ $BW -gt 14 ]; then + BW=$(($(echo $BW) / 5)) + else + BW="1.4" + fi + BAND=${BAND:1} + if [ "$CELLTYPE" -eq 1 ]; then + BAND="B"$(($BAND + 0))" (Bandwidth: "$BW" MHz)" + else + BAND="B"$(($BAND + 0))" (CA, Bandwidth: "$BW" MHz)" + fi + fi + if [ "$CRAT" -eq 9 ]; then + SSINR=$(echo $CCVAL | cut -d, -f11 | grep -o "[0-9]\{1,3\}") + if [ -n "$SSINR" ] && [ "$SSINR" != "255" ]; then + SSINR=$((($SSINR - 47) / 2))" dB" + else + SSINR="-" + fi + if [ -n "$SINR" ]; then + SINR=$SINR"
                                                                        "$SSINR + else + SINR=$SSINR + fi + if [ "$CELLTYPE" -eq 1 ]; then + BAND="n"${BAND:2}" (Bandwidth: "$BW" MHz)" + else + BAND="n"${BAND:2}" (CA, Bandwidth: "$BW" MHz)" + fi + fi + if [ -n "$LBAND" ]; then + LBAND=$LBAND"
                                                                        "$BAND + else + LBAND=$BAND + fi + if [ -n "$CHANNEL" ]; then + CHANNEL=$CHANNEL","$CHAN + else + CHANNEL=$CHAN + fi + if [ -n "$PCI" ]; then + PCI=$PCI","$PCID + else + PCI=$PCID + fi + if [ "$CELLTYPE" -eq 1 ]; then + RSRP=$(echo $CCVAL | cut -d, -f13) + RSRQ=$(echo $CCVAL | cut -d, -f14) + if [ "$RSRP" -ne 255 ] && [ "$RSRQ" -ne 255 ]; then + decode_signal + RSSI=$(rsrp2rssi $RSCPs $BW) + CSQ_PER=$((100 - (($RSSI + 51) * 100/-62)))"%" + CSQ=$((($RSSI + 113) / 2)) + CSQ_RSSI=$RSSI" dBm" + fi + fi + done +fi + +if [ -n "$GTCCDATAy" ]; then + CHANNEL=$(echo $GTCCDATAy | cut -d, -f7) + BW=$(echo $GTCCDATAy | cut -d, -f10) + decode_bw + LBAND="B"$(echo $GTCCDATAy | cut -d, -f9)" (Bandwidth: "$BW" MHz)" + XUDATA="" +fi + +if [ -n "$XLDATA" ]; then + XLDATA=$(echo "${XLDATA//[\" ]/}") + XLEC=$(echo $OX | grep -o "+XLEC: [01],[0-9]\+,[0-5],.*BAND_LTE_[0-9]\{1,2\},[^ ]\+") + MODE="LTE" + PCI=$(echo $XLDATA | cut -d, -f6) + PCI=$(printf "%d" $PCI) + CHANNEL=$(echo $XLDATA | cut -d, -f7) + CHANNEL=$(printf "%d" $CHANNEL) + LBAND=$($ROOTER/chan2band.sh "$CHANNEL") + if [ -n "$XLEC" ]; then + BW=$(echo $XLEC | cut -d, -f3) + RAWLIST=$(echo $XLEC | grep -o "BAND_LTE_[0-9]\{1,2\}.\+" | grep -o "[,0-9]*" | tr ',' ' ') + BANDLIST="" + for BAND in $(echo "$RAWLIST"); do + if [ -n "$BAND" -a "$BAND" != "0" ]; then + if [ -n "$BANDLIST" ]; then + BANDLIST="$BANDLIST,$BAND" + else + BANDLIST="$BAND" + fi + fi + done + BAND="B"$(echo $BANDLIST | cut -d, -f1) + if [ "$BAND" = "$LBAND" ]; then + decode_bw + LBAND=$LBAND" (Bandwidth $BW MHz)" + NUMBR=$(echo $XLEC | cut -d, -f2) + for JJ in $(seq 2 $NUMBR); do + BAND=$(echo $BANDLIST | cut -d, -f$JJ) + if [ -n "$BAND" -a "$BAND" != "0" ]; then + KK=$(($JJ + 2)) + BW=$(echo $XLEC | cut -d, -f$KK) + decode_bw + if [ $BW != "-" ]; then + LBAND=$LBAND"
                                                                        B$BAND (CA, Bandwidth $BW MHz)" + fi + fi + done + fi + else + XLEC=$(echo $OX | grep -o "+XLEC: 0,[1-9],[0-5]") + if [ -n "$XLEC" ]; then + BW=$(echo $XLEC | cut -d, -f3) + decode_bw + LBAND=$LBAND" (Bandwidth $BW MHz)" + fi + fi + RSRP=$(echo $XLDATA | cut -d, -f10) + if [ $RSRP == 0 ]; then + RSRP=1 + fi + RSCP=$(($RSRP - 141)) + ECIO=$(echo $XLDATA | cut -d, -f11) + ECIO=$((($ECIO / 2) - 20)) + SINR=$(echo $XLDATA | cut -d, -f12 | grep -o "[-0-9]\{1,4\}") + if [ -n "$SINR" ] && [ "$SINR" != "255" ]; then + SINR=$(($SINR / 2))" dB" + fi + RSSI=$(rsrp2rssi $RSCP $BW) + CSQ_PER=$((100 - (($RSSI + 51) * 100/-62)))"%" + CSQ=$((($RSSI + 113) / 2)) + CSQ_RSSI=$RSSI" dBm" +fi +if [ -n "$XUDATA" ]; then + MODE="UMTS" + CHANNEL=$(echo $XUDATA | cut -d, -f7) + CHANNEL=${CHANNEL:1:10} + CHANNEL=$(printf "%d" $CHANNEL) + RSCP=$(echo $XUDATA | cut -d, -f11) + RSCP=$(($RSCP - 121)) + ECIO=$(echo $XUDATA | cut -d, -f12) + ECIO=$((($ECIO / 2) - 24)) +fi +if [ -n "$CADATA1" ]; then + RSCP="" + ECIO="" + BW=$(echo $CADATA1 | cut -d, -f13) + decode_bw + BWD=$BW + BW=$(echo $CADATA1 | cut -d, -f14) + decode_bw + BWU=$BW + LBAND="B"$(echo $CADATA1 | cut -d, -f2)" (Bandwidth $BWD MHz Down | $BWU MHz Up)" + CHANNEL=$(echo $CADATA1 | cut -d, -f11) + MODE="LTE" + CRAT="4" + RSRP=$(echo $CADATA1 | cut -d, -f8) + RSRQ=$(echo $CADATA1 | cut -d, -f9) + if [ "$RSRP" -ne 255 ] && [ "$RSRQ" -ne 255 ]; then + decode_signal + RSSI=$(rsrp2rssi $RSCPs $BWD) + CSQ_PER=$((100 - (($RSSI + 51) * 100/-62)))"%" + CSQ=$((($RSSI + 113) / 2)) + CSQ_RSSI=$RSSI" dBm" + else + RSRP="-" + RSRQ="-" + fi + PCI=$(echo $CADATA1 | cut -d, -f7) +fi +if [ -n "$CADATA2" ]; then + CADATA2=$(echo "${CADATA2//[ ]/}") + for CAVAL in $(echo "$CADATA2"); do + BW=$(echo $CAVAL | cut -d, -f9) + decode_bw + BWD=$BW + BW=$(echo $CAVAL | cut -d, -f10) + decode_bw + BWU=$BW + LBAND=$LBAND"
                                                                        B"$(echo $CAVAL | cut -d, -f2) + if [ $BWU = "-" ]; then + LBAND=$LBAND" (CA, Bandwidth: "$BWD" MHz)" + else + LBAND=$LBAND" (CA, Bandwidth $BWD MHz Down | $BWU MHz Up)" + fi + CHAN=$(echo $CAVAL | cut -d, -f7) + CHANNEL=$(echo "$CHANNEL", "$CHAN") + PCIX=$(echo $CAVAL | cut -d, -f3) + PCI=$(echo "$PCI", "$PCIX") + done +fi +if [ -n "$CADATA3" ]; then + CADATA3=$(echo "${CADATA3//[ ]/}") + for CAVAL in $(echo "$CADATA3"); do + BAND=$(echo $CAVAL | cut -d, -f3) + BAND=${BAND:1} + PCIX=$(echo $CAVAL | cut -d, -f4) + PCI=$(echo "$PCI", "$PCIX") + CHAN=$(echo $CAVAL | cut -d, -f5) + CHANNEL=$(echo "$CHANNEL", "$CHAN") + BW=$(echo $CAVAL | cut -d, -f6) + if [ $BW -gt 14 ]; then + BW=$(($(echo $BW) / 5)) + else + BW="1.4" + fi + LBAND=$LBAND"
                                                                        B"$(($BAND + 0))" (CA, Bandwidth: "$BW" MHz)" + done +fi + +MTEMP=$(echo $OX | grep -o "+MTSM: [0-9.]\{1,5\}") +if [ -n "$MTEMP" ]; then + CTEMP=$(echo $MTEMP | grep -o "[0-9.]\{1,5\}")$(printf "\xc2\xb0")"C" +fi + +MODTYPE="9" +MRAT=$(echo $OX | grep -o "+GTRAT: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") +if [ -n "$MRAT" ]; then +# If user inserted different SIM card, the Rat order will recover to default value (AT Commands manual) + case $MRAT in + "2" ) + NETMODE="5" ;; + "3" ) + NETMODE="7" ;; + "14" ) + NETMODE="9" ;; + "17"|"20" ) + NETMODE="8" ;; + * ) + NETMODE="1" ;; + esac +fi +XACT=$(echo $OX | grep -o "+XACT: [0-9]" | grep -o "[0-9]") +if [ -n "$XACT" ]; then + PREF=$(echo $OX | grep -o "+XACT: [0-9],[0-9]" | grep -o ",[0-9]") + case $XACT in + "1" ) + NETMODE="5" ;; + "2" ) + NETMODE="7" ;; + "4" ) + if [ "$PREF" = ",1" ]; then + NETMODE="4" + else + NETMODE="6" + fi ;; + * ) + NETMODE="6" ;; + esac +fi +CMODE=$(uci -q get modem.modem$CURRMODEM.cmode) +if [ "$CMODE" = 0 ]; then + NETMODE="10" +fi +if [ -z "$SINR" ]; then + SINR="-" +fi + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'PCI="'"$PCI"'"' + echo 'TEMP="'"$CTEMP"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file +if [ -n "$COPS_MCC" ]; then + echo 'COPS_MCC="'"$COPS_MCC"'"' >> /tmp/signal$CURRMODEM.file + echo 'COPS_MNC="'"$COPS_MNC"'"' >> /tmp/signal$CURRMODEM.file +fi +if [ -n "$COPX" ]; then + echo 'COPS="'"$COPX"'"' >> /tmp/signal$CURRMODEM.file +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/gettype.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/gettype.sh new file mode 100644 index 0000000..19fad9f --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/gettype.sh @@ -0,0 +1,213 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +echo "0" > /tmp/block + +decode_crsm() { + i=0 + while [ $i -lt $length ]; do + c1=${sstring:$i:1} + let 'j=i+1' + c2=${sstring:$j:1} + xstring=$xstring$c2$c1 + let 'i=i+2' + done +} + +CURRMODEM=$1 +CPORT=$(uci get modem.modem$CURRMODEM.commport) + +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "gettype.gcom" "$CURRMODEM") +OX=$($ROOTER/common/processat.sh "$OX") + +MANUF=$(echo "$OX" | awk -F[:] '/Manufacturer:/ { print $2}') + +if [ -z "$MANUF" ]; then + ATCMDD="AT+CGMI" + MANUF=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + MANUF=$(echo $MANUF) + MANUF=$(echo "${MANUF//[\"]/}") + MANUF=${MANUF::-3} + MPREFIX=${MANUF::8} + if [ "$MPREFIX" = "AT+CGMI " ]; then + MANUF=$(echo $MANUF | cut -c 9-) + fi + MPREFIX=${MANUF::7} + if [ "$MPREFIX" = "+CGMI: " ]; then + MANUF=$(echo $MANUF | cut -c 8-) + fi +fi +if [ -z "$MANUF" ]; then + MANUF=$(uci get modem.modem$CURRMODEM.manuf) +fi + +MODEL=$(echo "$OX" | awk -F[,\ ] '/^\+MODEL:/ {print $2}') + +if [ -z "$MODEL" ]; then + ATCMDD="AT+CGMM" + MODEL=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + MODEL=$(echo $MODEL) + MODEL=$(echo "${MODEL//[\"]/}") + MODEL=${MODEL::-3} + MPREFIX=${MODEL::8} + if [ "$MPREFIX" = "AT+CGMM " ]; then + MODEL=$(echo $MODEL | cut -c 9-) + fi + MPREFIX=${MODEL::7} + if [ "$MPREFIX" = "+CGMM: " ]; then + MODEL=$(echo $MODEL | cut -c 8-) + fi + MODEL=$(echo $MODEL | cut -d, -f1) +fi +if [ -z "$MODEL" ]; then + MODEL=$(uci get modem.modem$CURRMODEM.model) +fi + +uci set modem.modem$CURRMODEM.manuf="$MANUF" +uci set modem.modem$CURRMODEM.model="$MODEL" +uci commit modem + +$ROOTER/signal/status.sh $CURRMODEM "$MANUF $MODEL" "Connecting" + +IMEI=$(echo "$OX" | awk -F[,\ ] '/^\IMEI:/ {print $2}') + +if [ -z "$IMEI" ]; then + ATCMDD="AT+CGSN" + IMEI=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + IMEI=$(echo $IMEI | grep -o "[0-9]\{15\}") +fi + +if [ -z "$IMEI" ]; then + ATCMDD="ATI5" + IMEI=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + IMEI=$(echo $IMEI | grep -o "[0-9]\{15\}") +fi + +if [ -n "$IMEI" ]; then + IMEI=$(echo "$IMEI" | sed -e 's/"//g') + IMEI=${IMEI:0:15} +else + IMEI="Unknown" +fi +uci set modem.modem$CURRMODEM.imei=$IMEI + +IDP=$(uci get modem.modem$CURRMODEM.idP) +IDV=$(uci get modem.modem$CURRMODEM.idV) + +echo $IDV" : "$IDP > /tmp/msimdatax$CURRMODEM +echo "$IMEI" >> /tmp/msimdatax$CURRMODEM + +lua $ROOTER/signal/celltype.lua "$MODEL" $CURRMODEM +source /tmp/celltype$CURRMODEM +rm -f /tmp/celltype$CURRMODEM + +uci set modem.modem$CURRMODEM.celltype=$CELL +uci commit modem + +$ROOTER/luci/celltype.sh $CURRMODEM + +M2=$(echo "$OX" | grep -o "+CNUM:[^,]*,[^,]*,[0-9]\{3\}")"," +M2=${M2:6} +CNUMx=$(echo "$M2" | cut -d, -f1 | cut -d\" -f2) +CNUMx=$(echo $CNUMx) +CNUM=$(echo "$M2" | cut -d, -f2 | cut -d\" -f2) +CNUMtype=$(echo "$M2" | cut -d, -f3) +if [ "${CNUM:0:1}" != "+" -a "$CNUMtype" == "145" ]; then + CNUM="+"$CNUM +fi +if [ -z "$CNUM" ]; then + CNUM="*" +fi +if [ -z "$CNUMx" ]; then + CNUMx="*" +fi + +NLEN=$(echo "$OX" | awk -F[,\ ] '/^\+CPBR:/ {print $4}') +if [ "x$NLEN" != "x" ]; then + NLEN=$(echo "$NLEN" | sed -e 's/"//g') +else + NLEN="14" +fi +echo 'NLEN="'"$NLEN"'"' > /tmp/namelen$CURRMODEM + +ATCMDD="ATE1" +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +ATCMDD="AT+CTZU=1" +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +ATCMDD="AT\$QCPBMPREF?" +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +PBzero=$(echo "$OX" | grep "0") +if [ -n "$PBzero" ]; then + ATCMDD="AT\$QCPBMPREF=1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +fi +if [ "$IDV" == "2c7c" ]; then + ATCMDD="AT+QLWCFG=\"startup\"" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + LWon=$(echo "$OX" | grep "1") + if [ -n "$LWon" ]; then + ATCMDD="AT+QLWCFG=\"startup\",0" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + ATCMDD="AT+QCFG=\"ims\"" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + IMSon=$(echo "$OX" | grep "1") + if [ -z "$IMSon" ]; then + ATCMDD="AT+QCFG=\"ims\",1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi +fi +ATCMDD="AT+CIMI" +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +OX=$($ROOTER/common/processat.sh "$OX") +ERROR="ERROR" +if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` +then + ATCMDD="AT+CRSM=176,28423,0,0,9" + sstring=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD" | grep -o "[0-9F]\{18\}") + if [ -n "$sstring" ]; then + length=${#sstring} + decode_crsm + IMSI=${xstring:3} + else + IMSI="Unknown" + fi +else + OX=${OX//[!0-9]/} + IMSIL=${#OX} + IMSI=${OX:0:$IMSIL} +fi +echo "$IMSI" >> /tmp/msimdatax$CURRMODEM +uci set modem.modem$CURRMODEM.imsi=$IMSI + +ATCMDD="AT+CRSM=176,12258,0,0,10" +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +OX=$($ROOTER/common/processat.sh "$OX") +ERROR="ERROR" +if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` +then + ICCID="Unknown" +else + ICCID=$(echo "$OX" | awk -F[,\ ] '/^\+CRSM:/ {print $4}') + if [ "x$ICCID" != "x" ]; then + sstring=$(echo "$ICCID" | sed -e 's/"//g') + length=${#sstring} + xstring="" + decode_crsm + ICCID=$xstring + else + ICCID="Unknown" + fi +fi +uci set modem.modem$CURRMODEM.iccid=$ICCID +uci commit modem +echo "$ICCID" >> /tmp/msimdatax$CURRMODEM +echo "0" >> /tmp/msimdatax$CURRMODEM +echo "$CNUM" > /tmp/msimnumx$CURRMODEM +echo "$CNUMx" >> /tmp/msimnumx$CURRMODEM + +mv -f /tmp/msimdatax$CURRMODEM /tmp/msimdata$CURRMODEM +mv -f /tmp/msimnumx$CURRMODEM /tmp/msimnum$CURRMODEM + +rm -f /tmp/block diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/huaweidata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/huaweidata.sh new file mode 100644 index 0000000..8134784 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/huaweidata.sh @@ -0,0 +1,299 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Huawei Data" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +fix_data() { + O=$($ROOTER/common/processat.sh "$OY") +} + +process_csq() { + CSQ=$(echo "$O" | awk -F[,\ ] '/^\+CSQ:/ {print $2}') + [ "x$CSQ" = "x" ] && CSQ=-1 + if [ $CSQ -ge 0 -a $CSQ -le 31 ]; then + CSQ_PER=$(($CSQ * 100/31)) + CSQ_RSSI=$((2 * CSQ - 113)) + CSQX=$CSQ_RSSI + [ $CSQ -eq 0 ] && CSQ_RSSI="<= "$CSQ_RSSI + [ $CSQ -eq 31 ] && CSQ_RSSI=">= "$CSQ_RSSI + CSQ_PER=$CSQ_PER"%" + CSQ_RSSI=$CSQ_RSSI" dBm" + else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" + fi +} + +process_huawei() { + CSNR=$(echo "$O" | awk -F[,\ ] '/^\^CSNR:/ {print $2}') + if [ "x$CSNR" != "x" ]; then + RSCP=$CSNR + CSNR=$(echo "$O" | awk -F[,\ ] '/^\^CSNR:/ {print $3}') + if [ "x$CSNR" != "x" ]; then + ECIO=$CSNR + else + ECIO=`expr $RSCP - $CSQX` + fi + else + EC=$(echo "$O" | awk -F[,\ ] '/^\+CSQ:/ {print $4}') + if [ "x$EC" != "x" ]; then + ECIO=$EC + EX=$(printf %.0f $ECIO) + RSCP=`expr $CSQX + $EX` + fi + fi + + HCSQ=$(echo "$O" | grep -o "\^HCSQ:[ ]*\"LTE\",[^,]*,[^,]*,[0-9]\{1,3\}") + if [ -n "$HCSQ" ]; then + SINR=$(echo $HCSQ | cut -d, -f4) + if [ $SINR -lt 255 ]; then + SINR=$((($SINR / 5) - 20)) + else + SINR="-" + fi + fi + + LTERSRP=$(echo "$O" | awk -F[,\ ] '/^\^LTERSRP:/ {print $2}') + if [ "x$LTERSRP" != "x" ]; then + RSCP=$LTERSRP + LTERSRP=$(echo "$O" | awk -F[,\ ] '/^\^LTERSRP:/ {print $3}') + if [ "x$LTERSRP" != "x" ]; then + ECIO=$LTERSRP + else + ECIO=`expr $RSCP - $CSQX` + fi + fi + LBANDS=$(echo $O | grep -o "\^HFREQINFO:[0-9,]\+") + LBAND="" + CHANNEL="" + printf '%s\n' "$LBANDS" | while read LBANDL; do + CHANN=$(echo $LBANDL | cut -d, -f4 | grep -o "[0-9]\{2,6\}") + if [ -z "$CHANN" ]; then + LBAND="" + CHANNEL="" + else + BWU=$(($(echo $LBANDL | cut -d, -f9) / 1000)) + BWD=$(($(echo $LBANDL | cut -d, -f6) / 1000)) + LBANDL=$(echo $LBANDL | cut -d, -f3) + if [ -z "$LBANDL" ]; then + LBAND="" + else + if [ -n "$LBAND" ]; then + LBAND=$LBAND" aggregated with:
                                                                        " + fi + LBAND=$LBAND"B"$LBANDL" (Bandwidth $BWD MHz Down | $BWU MHz Up)" + fi + if [ -n "$CHANN" ]; then + if [ -n "$CHANNEL" ]; then + CHANNEL=$CHANNEL", "$CHANN + else + CHANNEL=$CHANN + fi + fi + + fi + { + echo "$LBAND" + echo "$CHANNEL" + } > /tmp/lbandvar$CURRMODEM + done + if [ -e /tmp/lbandvar$CURRMODEM ]; then + { + read LBAND + read CHANNEL + } < /tmp/lbandvar$CURRMODEM + rm /tmp/lbandvar$CURRMODEM + fi + if [ -z "$LBAND" ]; then + LBAND="-" + fi + if [ -z "$CHANNEL" ]; then + CHANNEL="-" + fi + + NETMODE="0" + SYSCFG=$(echo "$O" | awk -F[,\"] '/^\^SYSCFGEX:/ {print $2}') + if [ "x$SYSCFG" != "x" ]; then + MODTYPE="3" + case $SYSCFG in + "00" ) + NETMODE="1" + ;; + "01" ) + NETMODE="3" + ;; + "02" ) + NETMODE="5" + ;; + "03" ) + NETMODE="7" + ;; + * ) + ACQ=${SYSCFG:0:2} + case $ACQ in + "01" ) + NETMODE="2" + ;; + "02" ) + NETMODE="4" + ;; + "03" ) + NETMODE="6" + ;; + esac + ;; + esac + else + SYSCFG=$(echo "$O" | awk -F[,\ ] '/^\^SYSCFG:/ {print $2}') + if [ "x$SYSCFG" != "x" ]; then + MODTYPE="4" + case $SYSCFG in + "7" ) + NETMODE="1" + ;; + "13" ) + NETMODE="3" + ;; + "14" ) + NETMODE="5" + ;; + * ) + SYSCFG=$(echo "$O" | awk -F[,\ ] '/^\^SYSCFG:/ {print $3}') + case $SYSCFG in + "0" ) + NETMODE="1" + ;; + "1" ) + NETMODE="2" + ;; + "2" ) + NETMODE="4" + ;; + esac + ;; + esac + fi + fi + + NETMODEx=$(uci get modem.modem$CURRMODEM.netmode) + if [ "$NETMODE" != "$NETMODEx" ]; then + uci set modem.modem$CURRMODEM.netmode="$NETMODE" + uci commit modem + fi + + MODE="-" + TECH=$(echo "$O" | awk -F[,] '/^\^SYSINFOEX:/ {print $9}' | sed 's/"//g') + if [ "x$TECH" != "x" ]; then + MODE="$TECH" + fi + + if [ "x$MODE" = "x-" ]; then + TECH=$(echo "$O" | awk -F[,\ ] '/^\^SYSINFO:/ {print $8}') + if [ "x$TECH" != "x" ]; then + case $TECH in + 17*) MODE="HSPA+ (64QAM)";; + 18*) MODE="HSPA+ (MIMO)";; + 1*) MODE="GSM";; + 2*) MODE="GPRS";; + 3*) MODE="EDGE";; + 4*) MODE="WCDMA";; + 5*) MODE="HSDPA";; + 6*) MODE="HSUPA";; + 7*) MODE="HSPA";; + 9*) MODE="HSPA+";; + *) MODE=$TECH;; + esac + fi + fi + + TEMP=$(echo "$O" | awk -F[,] '/^\^CHIPTEMP:/ {print $2}') + if [ "x$TEMP" != "x" ]; then + TEMP=$((TEMP / 10))$(printf "\xc2\xb0")"C" + else + TEMP="unknown" + fi + + CMODE=$(uci get modem.modem$CURRMODEM.cmode) + if [ $CMODE = 0 ]; then + NETMODE="10" + fi +} + +CSQ="-" +CSQ_PER="-" +CSQ_RSSI="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +CHANNEL="-" +LBAND="-" +MODETYPE="-" +NETMODE="-" +TEMP="-" +PCI="-" +SINR="-" + +OY=$($ROOTER/gcom/gcom-locked "$COMMPORT" "huaweiinfo.gcom" "$CURRMODEM") + +fix_data +process_csq +process_huawei + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'PCI="'"$PCI"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +CONNECT=$(uci get modem.modem$CURRMODEM.connected) +if [ $CONNECT -eq 0 ]; then + exit 0 +fi + +if [ $CSQ = "-" ]; then + log "$OY" +fi + +ENB="0" +if [ -e /etc/config/failover ]; then + ENB=$(uci get failover.enabled.enabled) +fi +if [ $ENB = "1" ]; then + exit 0 +fi + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/lockchk.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/lockchk.sh new file mode 100644 index 0000000..5d096ad --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/lockchk.sh @@ -0,0 +1,104 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Lock Provider" "$@" +} + +setautocops() { + if [ "$MODTYPE" = "2" -o "$MODTYPE" = "6" -o "$MODTYPE" = "8" -o "$MODTYPE" = "11" ]; then + NETMODE=$(uci get modem.modem$CURRMODEM.netmode) + case $NETMODE in + "3") + ATCMDD="AT+COPS=0,,,0" ;; + "5") + ATCMDD="AT+COPS=0,,,2" ;; + "7") + ATCMDD="AT+COPS=0,,,7" ;; + "8") + ATCMDD="AT+COPS=0,,,13" ;; + "9") + ATCMDD="AT+COPS=0,,,12" ;; + *) + ATCMDD="AT+COPS=0" ;; + esac + else + ATCMDD="AT+COPS=0" + fi + OX=$($ROOTER/gcom/gcom-locked "$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + CLOG=$(uci get modem.modeminfo$CURRMODEM.log) + if [ $CLOG = "1" ]; then + log "$OX" + fi + exit 0 +} + +CURRMODEM=$1 +if [ -e /usr/lib/netroam/lock.sh ]; then + if [ -e /tmp/rlock ]; then + /usr/lib/netroam/lock.sh $CURRMODEM + exit 0 + fi +fi +CPORT=/dev/ttyUSB$(uci get modem.modem$CURRMODEM.commport) +MODTYPE=$(uci get modem.modem$CURRMODEM.modemtype) +LOCK=$(uci get modem.modeminfo$CURRMODEM.lock) +if [ "$LOCK" = "2" ]; then + LOCK="4" +fi +ATCMDD="AT+COPS=3,2;+COPS?" +OX=$($ROOTER/gcom/gcom-locked "$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +COPSMODE=$(echo $OX | grep -o "+COPS:[ ]\?[014]" | grep -o "[014]") +COPSPLMN=$(echo $OX | grep -o "[0-9]\{5,6\}") + +if [ -z "$LOCK" -o "$LOCK" = "0" ]; then + if [ "$COPSMODE" = "0" ]; then + exit 0 + fi + setautocops +fi +MCC=$(uci -q get modem.modeminfo$CURRMODEM.mcc) +LMCC=${#MCC} +if [ $LMCC -ne 3 ]; then + setautocops +fi +MNC=$(uci -q get modem.modeminfo$CURRMODEM.mnc) +if [ -z $MNC ]; then + setautocops +fi +LMNC=${#MNC} +if [ $LMNC -eq 1 ]; then + MNC=0$MNC +fi +if [ "$COPSMODE$COPSPLMN" = "$LOCK$MCC$MNC" ]; then + exit 0 +fi +if [ "$MODTYPE" = "2" -o "$MODTYPE" = "6" -o "$MODTYPE" = "8" -o "$MODTYPE" = "11" ]; then + NETMODE=$(uci get modem.modem$CURRMODEM.netmode) + case $NETMODE in + "3") + ATCMDD="AT+COPS=$LOCK,2,\"$MCC$MNC\",0" ;; + "5") + ATCMDD="AT+COPS=$LOCK,2,\"$MCC$MNC\",2" ;; + "7") + ATCMDD="AT+COPS=$LOCK,2,\"$MCC$MNC\",7" ;; + "8") + ATCMDD="AT+COPS=$LOCK,2,\"$MCC$MNC\",13" ;; + "9") + ATCMDD="AT+COPS=$LOCK,2,\"$MCC$MNC\",12" ;; + *) + ATCMDD="AT+COPS=$LOCK,2,\"$MCC$MNC\"" ;; + esac +else + ATCMDD="AT+COPS=$LOCK,2,\"$MCC$MNC\"" +fi + +OX=$($ROOTER/gcom/gcom-locked "$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +CLOG=$(uci get modem.modeminfo$CURRMODEM.log) +if [ $CLOG = "1" ]; then + log "Error While Locking to Provider" + log "$OX" +else + log "Locked to Provider $MCC $MNC" +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/mdm9215data.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/mdm9215data.sh new file mode 100644 index 0000000..c552b0a --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/mdm9215data.sh @@ -0,0 +1,127 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "MDM9215 Data" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "mdm9215info.gcom" "$CURRMODEM" | tr 'a-z' 'A-Z') +O=$($ROOTER/common/processat.sh "$OX") +O=$(echo $O) + +RSRP="" +RSRQ="" +CHANNEL="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +MODTYPE="-" +NETMODE="-" +LBAND="-" +TEMP="-" +PCI="-" +SINR="-" + +Oup=$(echo $O | tr 'a-z' 'A-Z') + +CSQ=$(echo $O | grep -o "CSQ: [0-9]\+" | grep -o "[0-9]\+") +[ "x$CSQ" = "x" ] && CSQ=-1 + +if [ $CSQ -ge 0 -a $CSQ -le 31 ]; then + CSQ_PER=$(($CSQ * 100/31)) + CSQ_RSSI=$((2 * CSQ - 113)) + CSQX=$CSQ_RSSI + [ $CSQ -eq 0 ] && CSQ_RSSI="<= "$CSQ_RSSI + [ $CSQ -eq 31 ] && CSQ_RSSI=">= "$CSQ_RSSI + CSQ_PER=$CSQ_PER"%" + CSQ_RSSI=$CSQ_RSSI" dBm" +else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" +fi + +MODE="-" +WS46=$(echo $O" " | grep -o "+COPS: .\+ OK " | tr " " ",") +TECH=$(echo $WS46 | cut -d, -f5) + +if [ ! -z "$TECH" ]; then + MODE=$TECH + SGCELL=$(echo $O" " | grep -o "\$QCSQ .\+ OK " | tr " " "," | tr ",:" ",") + + WS46=$(echo $O" " | grep -o "AT\$QCSYSMODE? .\+ OK ") + WS46=$(echo "$WS46" | sed -e "s/AT\$QCSYSMODE? //g") + WS46=$(echo "$WS46" | sed -e "s/ OK//g") + + case $MODE in + *) + RSCP=$(echo $SGCELL | cut -d, -f8) + RSCP="-"$(echo $RSCP | grep -o "[0-9]\{1,3\}") + ECIO=$(echo $SGCELL| cut -d, -f5) + ECIO="-"$(echo $ECIO | grep -o "[0-9]\{1,3\}") + RSSI=$(echo $SGCELL | cut -d, -f4) + CSQ_RSSI="-"$(echo $RSSI | grep -o "[0-9]\{1,3\}")" dBm" + ;; + "7") + RSSI=$(echo $SGCELL | cut -d, -f4) + CSQ_RSSI=$(echo $RSSI | grep -o "[0-9]\{1,3\}")" dBm" + RSCP=$(echo $SGCELL | cut -d, -f8) + RSCP="-"$(echo $RSCP | grep -o "[0-9]\{1,3\}") + ECIO=$(echo $SGCELL| cut -d, -f4) + ECIO="-"$(echo $ECIO | grep -o "[0-9]\{1,3\}") + ;; + esac + + MODE=$WS46 +fi + +NETMODE="1" +MODTYPE="8" + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'PCI="'"$PCI"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +CONNECT=$(uci get modem.modem$CURRMODEM.connected) +if [ $CONNECT -eq 0 ]; then + exit 0 +fi + +if [ "$CSQ" = "-" ]; then + log "$OX" +fi + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/meigdata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/meigdata.sh new file mode 100644 index 0000000..360a708 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/meigdata.sh @@ -0,0 +1,281 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Meig Data" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "meiginfo.gcom" "$CURRMODEM" | tr 'a-z' 'A-Z') + +O=$($ROOTER/common/processat.sh "$OX") +O=$(echo $O) +OX=$(echo $OX) + +RSRP="" +RSRQ="" +CHANNEL="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +MODTYPE="-" +NETMODE="-" +LBAND="-" +TEMP="-" +PCI="-" +SINR="-" + +CSQ=$(echo $OX | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") +if [ "$CSQ" = "99" ]; then + CSQ="" +fi +if [ -n "$CSQ" ]; then + CSQ_PER=$(($CSQ * 100/31))"%" + CSQ_RSSI=$((2 * CSQ - 113))" dBm" +else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" +fi + +MODE="-" +PSRAT=$(echo $O" " | grep -o "+PSRAT: .\+ OK " | tr " " ",") +TECH=$(echo $PSRAT | cut -d, -f2) +if [ -n "$TECH" ]; then + MODE=$TECH +fi + +ATECH=$(echo $OX | grep -o "+SGCELLINFOEX:[^,]\{2,6\}," | grep -o ":[ ]\?[-A-Z5]\{2,6\}" | grep -o "[-A-Z5]\{2,6\}") +if [ -n "$ATECH" ]; then + MODE=$ATECH +fi + +SGCELL=$(echo $O" " | grep -o "+SGCELLINFO: .\+ OK " | tr " " ",") + +MODEx=$MODE +case $MODEx in + "TD-LTE"|"FDD-LTE"|"FDD" ) + RSSI=$(echo $SGCELL | cut -d, -f5) + CSQ_RSSI="-"$(echo $RSSI | grep -o "[0-9]\{1,3\}")" dBm" + RSCP=$(echo $SGCELL | cut -d, -f6) + RSCP="-"$(echo $RSCP | grep -o "[0-9]\{1,3\}") + ECIO=$(echo $SGCELL| cut -d, -f7) + ECIO="-"$(echo $ECIO | grep -o "[0-9]\{1,3\}") + SSINR=$(echo $SGCELL | cut -d, -f8 | grep -o "[0-9]\{1,3\}") + if [ -n "$SSINR" -a "$SSINR" -le "250" ]; then + SINR=$((($SSINR / 5) - 20))" dB" + fi + LBAND=$(echo $SGCELL | cut -d, -f9) + LBAND=$(echo $LBAND | grep -o "[0-9]\{1,5\}") + let LBAND=LBAND-119 + LBAND="B"$LBAND + CHANNEL=$(echo $SGCELL | cut -d, -f10) + CHANNEL=$(echo $CHANNEL | grep -o "[0-9]\{1,5\}") + ICELL=$(echo $O" " | grep -o "+CELLINFO: .\+ OK " | tr " " ",") + PCI=$(echo $ICELL | cut -d, -f18) + PCI=$(echo $PCI | grep -o "[0-9]\{1,5\}") + if [ $MODE = "FDD" ]; then + MODE="FDD LTE" + fi + ;; + "LTE"|"EN-DC" ) + SGC=$(echo $OX | grep -o "+SGCELLINFOEX:[ ]\?[-CDELNTE]\{3,5\},.\+AT+CELLINFO") + MODE=$(echo $SGC | cut -d, -f2) + PCI=$(echo $SGC | cut -d, -f6) + LBAND="B"$(echo $SGC | cut -d, -f10) + BW=$(echo $SGC | cut -d, -f11 | grep -o "[0-9]\{1,3\}") + if [ $BW -gt 14 ]; then + let BW=BW/5 + else + BW="1.4" + fi + LBAND=$LBAND" (Bandwidth $BW Mhz)" + CHANNEL=$(echo $SGC | cut -d, -f12) + RSSI=$(echo $SGC | cut -d, -f14) + CSQ_RSSI=$(echo $RSSI | grep -o "[-0-9]\{1,3\}")" dBm" + RSCP=$(echo $SGC | cut -d, -f15) + ECIO=$(echo $SGC| cut -d, -f16) + SINR=$(echo $SGC | cut -d, -f18)" dB" + if [ $MODEx == "EN-DC" ]; then + NRSINR=$(echo $SGC | cut -d, -f31 | grep -o "[-0-9]\{1,4\}") + NRBAND=$(echo $SGC | cut -d, -f32 | grep -o "[0-9]\{1,3\}") + NRCHAN=$(echo $SGC | cut -d, -f33 | grep -o "[0-9]\{6,7\}") + NRBW=$(echo $SGC | cut -d, -f34 | grep -o "[0-9]\{1,3\}") + if [ -n "$NRBAND" -a -n "$NRCHAN" -a -n "$NRBW" -a -n $NRSINR ]; then + NRRSRP=$(echo $SGC | cut -d, -f29 | grep -o "[-0-9]\{2,4\}") + NRRSRQ=$(echo $SGC | cut -d, -f30 | grep -o "[-0-9]\{2,4\}") + NRPCI=$(echo $SGC | cut -d, -f35 | grep -o "[0-9]\{1,3\}") + let NRBW=NRBW/5 + LBAND=$LBAND"
                                                                        n"$NRBAND" (Bandwidth "$NRBW" MHz)" + RSCP=$RSCP" dBm
                                                                        "$NRRSRP + ECIO=$ECIO" dBm
                                                                        "$NRRSRQ + SINR=$SINR"
                                                                        "$((($NRSINR / 5) - 20))" dB" + CHANNEL=$CHANNEL","$NRCHAN + PCI=$PCI","$NRPCI + fi + fi + ;; + "5G" ) + SGC=$(echo $OX | grep -o "+SGCELLINFOEX:[ ]\?5G,.\+AT+CELLINFO") + MODE=$(echo $SGC | cut -d, -f2) + PCI=$(echo $SGC | cut -d, -f6) + LBAND="n"$(echo $SGC | cut -d, -f8) + BW=$(echo $SGC | cut -d, -f9 | grep -o "[0-9]\{1,3\}") + let BW=BW/5 + LBAND=$LBAND" (Bandwidth $BW Mhz)" + CHANNEL=$(echo $SGC | cut -d, -f12) + RSCP=$(echo $SGC | cut -d, -f15) + ECIO=$(echo $SGC| cut -d, -f16) + SINR=$(echo $SGC | cut -d, -f17) + SINR=$((($SINR / 5) - 20))" dB" + ;; + "HSPA+"|"HSUPA"|"HSDPA"|"WCDMA" ) + if [ -n "$ATECH" ]; then + SGC=$(echo $OX | grep -o "WCDMA,[0-9]\{3\},.\+AT+CELLINFO" | tr ' ' ',') + CHANNEL=$(echo $SGC | cut -d, -f11) + ECIO=$(echo $SGC | cut -d, -f14) + RSCP=$(echo $SGC | cut -d, -f16) + else + RSCP=$(echo $SGCELL | cut -d, -f11) + RSCP="-"$(echo $RSCP | grep -o "[0-9]\{1,3\}") + ECIO=$(echo $SGCELL| cut -d, -f12) + ECIO="-"$(echo $ECIO | grep -o "[0-9]\{1,3\}") + CHANNEL=$(echo $SGCELL | cut -d, -f8) + CHANNEL=$(echo $CHANNEL | grep -o "[0-9]\{1,4\}") + RSSI=$(echo $SGCELL | cut -d, -f10) + CSQ_RSSI=$(echo $RSSI | grep -o "[0-9]\{1,3\}")" dBm" + fi + ;; + *) + RSCP=$(echo $SGCELL | cut -d, -f10) + RSCP="-"$(echo $RSCP | grep -o "[0-9]\{1,3\}") + CHANNEL=$(echo $SGCELL | cut -d, -f8) + CHANNEL=$(echo $CHANNEL | grep -o "[0-9]\{1,4\}") + RSSI=$(echo $SGCELL | cut -d, -f9) + CSQ_RSSI=$(echo $RSSI | grep -o "[0-9]\{1,3\}")" dBm" + ;; +esac + +CALIST=$(echo "${OX//[ ]/}" | grep -o "+CELLINFO:\"SCC\",[0-9],2,[0-9],[0-9]\{1,6\},[0-9]\{1,4\},[0-9]\{1,3\},[0-9]\{1,3\},[-0-9]\{1,4\},[-0-9]\{1,4\},[-0-9]\{1,4\},[-0-9]\{1,4\}") + +for CAVAL in $(echo "$CALIST"); do + if [ "$(echo $CAVAL | cut -d, -f2)" == "1" ]; then + CATYPE="CA"$(printf "\xe2\x86\x91") + else + CATYPE="CA" + fi + CHANv=$(echo $CAVAL | cut -d, -f5) + BWv=$(echo $CAVAL | cut -d, -f6) + if [ $BWv -gt 14 ]; then + let BWv=BWv/5 + else + BWv="1.4" + fi + if [ $CHANv -ge 123400 ]; then + BANDv="n"$(echo $CAVAL | cut -d, -f7) + else + BANDv="B"$(echo $CAVAL | cut -d, -f7) + fi + LBAND=$LBAND"
                                                                        "$BANDv" ($CATYPE, Bandwidth "$BWv" MHz)" + PCI=$PCI","$(echo $CAVAL | cut -d, -f8) + ECIO=$ECIO" dBm
                                                                        "$(echo $CAVAL | cut -d, -f9) + RSCP=$RSCP" dBm
                                                                        "$(echo $CAVAL | cut -d, -f10) + SINRv=$(echo $CAVAL | cut -d, -f12) + SINRv=$((($SINRv / 5) - 20))" dB" + CHANNEL=$CHANNEL","$CHANv + SINR=$SINR"
                                                                        "$SINRv +done + +NETMODE="-" +NMODE=$(echo $O" " | grep -o "+MODODR: .\+ OK " | tr " " ",") +TECH=$(echo $NMODE | cut -d, -f2) +if [ -n "$TECH" ]; then + MODTYPE="7" + case $TECH in + "2" ) + NETMODE="1" # Auto + ;; + "1" ) + NETMODE="5" # 3G only + ;; + "4" ) + NETMODE="4" # 3G preferred + ;; + "3" ) + NETMODE="3" # 2G only + ;; + "5" ) + NETMODE="7" # LTE only + ;; + * ) + NETMODE="1" + ;; + esac +fi +RATs=$(echo "$OX" | grep -o "\^SYSCFGEX: \"[0-9]\{2,6\}\"" | grep -o "[0-9]\{2,6\}") +if [ -n "$RATs" ]; then + MODTYPE="7" + case $RATs in + "02" ) + NETMODE="5" ;; + "03" ) + NETMODE="7" ;; + "04" ) + NETMODE="9" ;; + "0203" | "0204" | "020304" | "020403" ) + NETMODE="4" ;; + "0304" | "0302" | "030402" | "030204" ) + NETMODE="6" ;; + "0403" ) + NETMODE="8" ;; + * ) + NETMODE="1" ;; + esac +fi + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'PCI="'"$PCI"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +CONNECT=$(uci get modem.modem$CURRMODEM.connected) +if [ "$CONNECT" == "0" ]; then + exit 0 +fi + +if [ "$CSQ" = "-" ]; then + log "$OX" +fi + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! "$OPER" ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/modemchk.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/modemchk.lua new file mode 100644 index 0000000..4598cd8 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/modemchk.lua @@ -0,0 +1,120 @@ +#!/usr/bin/lua + +local uvid = arg[1] +local upid = arg[2] +local dport = arg[3] +local cport = arg[4] + +local modemfile = "/etc/config/modem.data" +local modemdata = {} +local count +local retval +local cretval + +function process_line(xline, cnt) + local data = {} + local pline = xline + local start = 1 + for i=1,3 do + s, e = string.find(pline, " ") + data[i] = string.sub(pline, start, s-1) + pline = string.sub(pline, e+1) + end + data[4] = pline + modemdata[cnt] = data +end + +function read_modem() + count = 0 + local file = io.open(modemfile, "r") + if file == nil then + return + end + repeat + local line = file:read("*line") + if line == nil then + break + end + if string.len(line) < 5 then + break + end + count = count + 1 + process_line(line, count) + until 1==0 + file:close() +end + +function process_port() + for l=1,count do + local mdata = modemdata[l] + if mdata[1] == uvid and mdata[2] == upid then + retval = 0 + if mdata[3] == "tty0" then + retval = 1 + end + if mdata[3] == "tty1" then + retval = 2 + end + if mdata[3] == "tty2" then + retval = 3 + end + if mdata[3] == "tty3" then + retval = 4 + end + if mdata[3] == "tty4" then + retval = 5 + end + if mdata[3] == "tty5" then + retval = 6 + end + + cretval = 0 + if mdata[4] == "tty0" then + cretval = 1 + end + if mdata[4] == "tty1" then + cretval = 2 + end + if mdata[4] == "tty2" then + cretval = 3 + end + if mdata[4] == "tty3" then + cretval = 4 + end + if mdata[4] == "tty4" then + cretval = 5 + end + if mdata[4] == "tty5" then + cretval = 6 + end + + break + end + end +end + +read_modem() +retval = 0 +cretval = 0 +if count > 0 then + process_port() +end +if retval > 0 then + retval = retval - 1 +else + retval = tonumber(dport) +end +if cretval > 0 then + cretval = cretval - 1 +else + cretval = tonumber(cport) +end + +dret = string.format("%d", retval) +cret = string.format("%d", cretval) +local file = io.open("/tmp/parmpass", "w") +file:write("DPORT=\"" .. dret .. "\"\n") +file:write("CPORT=\"" .. cret .. "\"\n") +file:close() + +os.exit(retval) diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/novateldata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/novateldata.sh new file mode 100644 index 0000000..0b189ef --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/novateldata.sh @@ -0,0 +1,138 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Novatel Data" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +fix_data() { + OY=$(echo $OY | tr 'a-z' 'A-Z') + O=$($ROOTER/common/processat.sh "$OY") + O=$(echo $O" ") + O=$(echo "${O//[\"]/}") +} + +process_csq() { +CSQ=$(echo $OY | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") + if [ "$CSQ" = "99" ]; then + CSQ="" + fi + if [ -n "$CSQ" ]; then + CSQ_PER=$(($CSQ * 100/31))"%" + CSQ_RSSI=$((2 * CSQ - 113))" dBm" + else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" + fi +} + +CSQ="-" +CSQ_PER="-" +CSQ_RSSI="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +MODTYPE="-" +NETMODE="-" +LBAND="-" +CHANNEL="-" +TEMP="-" +PCI="-" +SINR="-" + +OY=$($ROOTER/gcom/gcom-locked "$COMMPORT" "novatelinfo.gcom" "$CURRMODEM") + +fix_data +process_csq + +DEG=$(echo $O" " | grep -o "+NWDEGC: .\+ OK " | tr " " ",") +TMP=$(echo $DEG | cut -d, -f2) +if [ -n "$TMP" ]; then + TEMP=$TMP$(printf "\xc2\xb0")"C" +fi + +MODE="-" +PSRAT=$(echo $O" " | grep -o "\$NWRAT: .\+ OK " | tr " " ",") +TECH=$(echo $PSRAT | cut -d, -f4) +if [ -n "$TECH" ]; then + case "$TECH" in + "1"|"2"|"3") + MODE="UMTS" + ;; + "4"|"5"|"6") + MODE="GSM" + ;; + "7"|"8"|"9") + MODE="LTE" + VZWRSRP=$(echo "$O" | grep -o "VZWRSRP: [0-9]\{1,3\},[0-9]\{1,7\},[-.0-9]\{1,7\}" | tr " " ",") + PCI=$(echo "$VZWRSRP" | cut -d, -f2) + CHANNEL=$(echo "$VZWRSRP" | cut -d, -f3) + LBAND=$("$ROOTER/chan2band.sh" "$CHANNEL") + TMP=$(echo "$VZWRSRP" | cut -d, -f4) + if [ -n "$TMP" ]; then + RSCP=$TMP + fi + VZWRSRQ=$(echo "$O" | grep -o "VZWRSRQ: [0-9]\{1,3\},[0-9]\{1,7\},[-.0-9]\{1,7\}" | tr " " ",") + TMP=$(echo "$VZWRSRQ" | cut -d, -f4) + if [ -n "$TMP" ]; then + ECIO=$TMP + fi + ;; + *) + MODE="CDMA/HDR" + ;; + esac +fi + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'PCI="'"$PCI"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +CONNECT=$(uci get modem.modem$CURRMODEM.connected) +if [ $CONNECT -eq 0 ]; then + exit 0 +fi + +ENB="0" +if [ -e /etc/config/failover ]; then + ENB=$(uci get failover.enabled.enabled) +fi +if [ $ENB = "1" ]; then + exit 0 +fi + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/otherdata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/otherdata.sh new file mode 100644 index 0000000..af68b66 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/otherdata.sh @@ -0,0 +1,97 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Other Data" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +fix_data() { + O=$($ROOTER/common/processat.sh "$OY") +} + +process_csq() { + CSQ=$(echo "$O" | awk -F[,\ ] '/^\+CSQ:/ {print $2}') + [ "x$CSQ" = "x" ] && CSQ=-1 + if [ $CSQ -ge 0 -a $CSQ -le 31 ]; then + CSQ_PER=$(($CSQ * 100/31)) + CSQ_RSSI=$((2 * CSQ - 113)) + CSQX=$CSQ_RSSI + [ $CSQ -eq 0 ] && CSQ_RSSI="<= "$CSQ_RSSI + [ $CSQ -eq 31 ] && CSQ_RSSI=">= "$CSQ_RSSI + CSQ_PER=$CSQ_PER"%" + CSQ_RSSI=$CSQ_RSSI" dBm" + else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" + fi +} + +CSQ="-" +CSQ_PER="-" +CSQ_RSSI="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +MODETYPE="-" +NETMODE="-" +LBAND="-" +TEMP="-" +PCI="-" +SINR="-" + +OY=$($ROOTER/gcom/gcom-locked "$COMMPORT" "otherinfo.gcom" "$CURRMODEM") + +fix_data +process_csq + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'PCI="'"$PCI"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +CONNECT=$(uci get modem.modem$CURRMODEM.connected) +if [ $CONNECT -eq 0 ]; then + exit 0 +fi + +ENB="0" +if [ -e /etc/config/failover ]; then + ENB=$(uci get failover.enabled.enabled) +fi +if [ $ENB = "1" ]; then + exit 0 +fi + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/phone.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/phone.sh new file mode 100644 index 0000000..cf0a8b9 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/phone.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Phone Change" "$@" +} + +CURRMODEM=$1 +PHONE=$2 +NAME=$3 + +CPORT=$(uci get modem.modem$CURRMODEM.commport) +PHONE=$(echo "$PHONE" | sed -e 's/ //g') + +log "Change Modem $CURRMODEM SIM phone number to $PHONE, name to $NAME" + +INTER=${PHONE:0:1} +if [ $INTER = "+" ]; then + TON="145" + PHONE=${PHONE:1} +else + TON="129" +fi + +ATCMDD="AT+CPBS=\"ON\";+CPBS?" +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +OX=$($ROOTER/common/processat.sh "$OX") + +ON=$(echo "$OX" | awk -F[,\ ] '/^\+CPBS:/ {print $2}') +if [ "$ON" = "\"ON\"" ]; then + ATCMDD="AT+CPBW=1,\"$PHONE\",$TON,\"$NAME\"" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ATCMDD="AT+CNUM" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$($ROOTER/common/processat.sh "$OX") + M2=$(echo "$OX" | grep -o "+CNUM:[^,]*,[^,]*,[0-9]\{3\}")"," + M2=${M2:6} + CNUMx=$(echo "$M2" | cut -d, -f1 | cut -d\" -f2) + CNUMx=$(echo $CNUMx) + CNUM=$(echo "$M2" | cut -d, -f2 | cut -d\" -f2) + CNUMtype=$(echo "$M2" | cut -d, -f3) + if [ "${CNUM:0:1}" != "+" -a "$CNUMtype" == "145" ]; then + CNUM="+"$CNUM + fi + if [ -z "$CNUM" ]; then + CNUM="*" + fi + if [ -z "$CNUMx" ]; then + CNUMx="*" + fi + echo "$CNUM" > /tmp/msimnumx$CURRMODEM + echo "$CNUMx" >> /tmp/msimnumx$CURRMODEM + mv -f /tmp/msimnumx$CURRMODEM /tmp/msimnum$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/processat.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/processat.sh new file mode 100644 index 0000000..16cba63 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/processat.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +OX=$1 + +M6=$(echo "$OX" | sed -e "s/ / /g") +M5=$(echo "$M6" | sed -e "s/ / /g") +M4=$(echo "$M5" | sed -e "s/ / /g") +M3=$(echo "$M4" | sed -e "s/ / /g") +M2=$(echo "$M3" | sed -e "s/ / /g") +M2=$(echo "$M2" | sed -e "s/TAC:/ /;s/Tx Power:/ /;s/SINR/ /;s!SYSINFOEX:!SYSINFOEX: !;s!CNTI:!CNTI: !;s!SELRAT:!SELRAT: !;s!ZSNT:!ZSNT: !") +M1=$(echo "$M2" | sed -e "s!Car0 Tot Ec/Io!+ECIOx!;s!Car1 Tot Ec/Io!+ECIO1x!;s!Car0 RSCP!+RSCPx!;s!+CGMM: !!") +M2=$(echo "$M1" | sed -e "s!Car1 RSCP!+RSCP1x!;s!CSNR:!CSNR: !;s!RSSI (dBm):!RSSI4: !;s!AirCard !AirCard!;s!USB !USB!") +M3=$(echo "$M2" | sed -e "s!RSRP (dBm):!RSRP4: !;s!RSRQ (dB):!RSRQ4: !;s!LTERSRP:!LTERSRP: !;s!Model:!+MODEL: !;s!SYSCFGEX:!SYSCFGEX: !") +M7=$(echo "$M3" | sed -e "s!RX level Carrier 0 (dBm):!RSSI3: !;s!RX level Carrier 1 (dBm):!RSSI13: !;s!SYSCFG:!SYSCFG: !;s! ! !g") +OX=$(echo "$M7" | sed -e "s!WCDMA channel:!UMTS:!;s!SYSINFO:!SYSINFO: !;s!+PSRAT:!+PSRAT: !;s!+MODODR:!+MODODR: !") +echo "$OX" \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/quantadata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/quantadata.sh new file mode 100644 index 0000000..729ef12 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/quantadata.sh @@ -0,0 +1,121 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Quanta Data" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "quantainfo.gcom" "$CURRMODEM") + +OX=$(echo $OX | tr 'a-z' 'A-Z') + +RSRP="" +RSRQ="" +CHANNEL="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +LBAND="-" +PCI="-" +SINR="-" +TEMP="-" + +CSQ=$(echo $OX | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") +if [ "$CSQ" = "99" ]; then + CSQ="" +fi +if [ -n "$CSQ" ]; then + CSQ_PER=$(($CSQ * 100/31))"%" + CSQ_RSSI=$((2 * CSQ - 113))" dBm" +else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" +fi + +REGX='*QRFINFO: \"LTE\",[0-9]\{1,2\},[0-9]\{1,5\},[.012345]\{1,3\},[0-9]\{1,3\},-[0-9]\{1,3\},[-0-9]\{1,3\},[.0-9]\{1,4\}' +LTE=$(echo $OX | grep -o "$REGX") +if [ -n "$LTE" ]; then + MODE="LTE" + BW=$(echo $LTE | cut -d, -f4) + LBAND="B"$(echo $LTE | cut -d, -f2)"(Bandwidth "$BW" MHz)" + RSCP=$(echo $LTE | cut -d, -f6) + ECIO=$(echo $LTE | cut -d, -f7) + CHANNEL=$(echo $LTE | cut -d, -f3) + PCI=$(echo $LTE | cut -d, -f5) + SINR=$(echo $LTE | cut -d, -f8)" dB" +else + REGX='*QRFINFO: \"WCDMA\",[0-9]\{1,2\},[0-9]\{1,5\},[^,],[0-9]\{1,3\},-[0-9]\{1,3\},[-0-9]\{1,3\}' + UMTS=$(echo $OX | grep -o "$REGX") + if [ -n "$UMTS" ]; then + MODE="WCDMA" + LBAND="B"$(echo $UMTS | cut -d, -f2) + RSCP=$(echo $UMTS | cut -d, -f6) + ECIO=$(echo $UMTS | cut -d, -f7) + CHANNEL=$(echo $UMTS | cut -d, -f3) + PCI=$(echo $UMTS | cut -d, -f5) + fi +fi + +TECH=$(echo $OX | grep -o "\^QCNCFG: \"[0123]\{2\}\"" | grep -o "[0123]\{2\}") +case $TECH in + "02") + NETMODE="5" + ;; + "03") + NETMODE="7" + ;; + *) + NETMODE="1" + ;; +esac + +MODTYPE="11" + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'PCI="'"$PCI"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +CONNECT=$(uci get modem.modem$CURRMODEM.connected) +if [ $CONNECT -eq 0 ]; then + exit 0 +fi + +if [ "$CSQ" = "-" ]; then + log "$OX" +fi + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/quecteldata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/quecteldata.sh new file mode 100644 index 0000000..d1d575a --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/quecteldata.sh @@ -0,0 +1,376 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +CURRMODEM=$1 +COMMPORT=$2 + +lte_bw() { + BW=$(echo $BW | grep -o "[0-5]\{1\}") + case $BW in + "0") + BW="1.4" ;; + "1") + BW="3" ;; + "2"|"3"|"4"|"5") + BW=$((($(echo $BW) - 1) * 5)) ;; + esac +} + +nr_bw() { + BW=$(echo $BW | grep -o "[0-9]\{1,2\}") + case $BW in + "0"|"1"|"2"|"3"|"4"|"5") + BW=$((($(echo $BW) + 1) * 5)) ;; + "6"|"7"|"8"|"9"|"10"|"11"|"12") + BW=$((($(echo $BW) - 2) * 10)) ;; + "13") + BW="200" ;; + "14") + BW="400" ;; + esac +} + +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "quectelinfo.gcom" "$CURRMODEM") + +OX=$(echo $OX | tr 'a-z' 'A-Z') + +RSRP="" +RSRQ="" +CHANNEL="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +MODTYPE="-" +NETMODE="-" +LBAND="-" +PCI="-" +CTEMP="-" +SINR="-" +CSQ=$(echo $OX | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") +if [ "$CSQ" = "99" ]; then + CSQ="" +fi +if [ -n "$CSQ" ]; then + CSQ_PER=$(($CSQ * 100/31))"%" + CSQ_RSSI=$((2 * CSQ - 113))" dBm" +else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" +fi +NR_NSA=$(echo $OX | grep -o "+QENG:[ ]\?\"NR5G-NSA\",") +NR_SA=$(echo $OX | grep -o "+QENG: \"SERVINGCELL\",[^,]\+,\"NR5G-SA\",\"[DFT]\{3\}\",") +if [ -n "$NR_NSA" ]; then + QENG=",,"$(echo $OX" " | grep -o "+QENG: \"LTE\".\+\"NR5G-NSA\"," | tr " " ",") + QENG5=$(echo $OX | grep -o "+QENG:[ ]\?\"NR5G-NSA\",[0-9]\{3\},[0-9]\{2,3\},[0-9]\{1,5\},-[0-9]\{2,5\},[-0-9]\{1,3\},-[0-9]\{2,3\},[0-9]\{1,7\},[0-9]\{1,3\}.\{1,6\}") + if [ -z "$QENG5" ]; then + QENG5=$(echo $OX | grep -o "+QENG:[ ]\?\"NR5G-NSA\",[0-9]\{3\},[0-9]\{2,3\},[0-9]\{1,5\},-[0-9]\{2,3\},[-0-9]\{1,3\},-[0-9]\{2,3\}") + if [ -n "$QENG5" ]; then + QENG5=$QENG5",," + fi + fi +elif [ -n "$NR_SA" ]; then + QENG=$(echo $NR_SA | tr " " ",") + QENG5=$(echo $OX | grep -o "+QENG: \"SERVINGCELL\",[^,]\+,\"NR5G-SA\",\"[DFT]\{3\}\",[ 0-9]\{3,4\},[0-9]\{2,3\},[0-9A-F]\{1,10\},[0-9]\{1,5\},[0-9A-F]\{2,6\},[0-9]\{6,7\},[0-9]\{1,3\},[0-9]\{1,2\},-[0-9]\{2,5\},-[0-9]\{2,3\},[-0-9]\{1,3\}") +else + QENG=$(echo $OX" " | grep -o "+QENG: [^ ]\+ " | tr " " ",") +fi +QCA=$(echo $OX" " | grep -o "+QCAINFO: \"S[CS]\{2\}\".\+NWSCANMODE" | tr " " ",") +QNSM=$(echo $OX | grep -o "+QCFG: \"NWSCANMODE\",[0-9]") +QNWP=$(echo $OX | grep -o "+QNWPREFCFG: \"MODE_PREF\",[A-Z5:]\+" | cut -d, -f2) +QTEMP=$(echo $OX | grep -o "+QTEMP: [0-9]\{1,3\}") +if [ -z "$QTEMP" ]; then + QTEMP=$(echo $OX | grep -o "+QTEMP:[ ]\?\"XO[_-]THERM[_-][^,]\+,[\"]\?[0-9]\{1,3\}" | grep -o "[0-9]\{1,3\}") +fi +if [ -z "$QTEMP" ]; then + QTEMP=$(echo $OX | grep -o "+QTEMP:[ ]\?\"MDM-CORE-USR.\+[0-9]\{1,3\}\"" | cut -d\" -f4) +fi +if [ -z "$QTEMP" ]; then + QTEMP=$(echo $OX | grep -o "+QTEMP:[ ]\?\"MDMSS.\+[0-9]\{1,3\}\"" | cut -d\" -f4) +fi +if [ -n "$QTEMP" ]; then + CTEMP=$(echo $QTEMP | grep -o "[0-9]\{1,3\}")$(printf "\xc2\xb0")"C" +fi +RAT=$(echo $QENG | cut -d, -f4 | grep -o "[-A-Z5]\{3,7\}") +rm -f /tmp/modnetwork +case $RAT in + "GSM") + MODE="GSM" + ;; + "WCDMA") + MODE="WCDMA" + CHANNEL=$(echo $QENG | cut -d, -f9) + RSCP=$(echo $QENG | cut -d, -f12) + RSCP="-"$(echo $RSCP | grep -o "[0-9]\{1,3\}") + ECIO=$(echo $QENG | cut -d, -f13) + ECIO="-"$(echo $ECIO | grep -o "[0-9]\{1,3\}") + ;; + "LTE"|"CAT-M"|"CAT-NB") + MODE=$(echo $QENG | cut -d, -f5 | grep -o "[DFT]\{3\}") + if [ -n "$MODE" ]; then + MODE="$RAT $MODE" + else + MODE="$RAT" + fi + PCI=$(echo $QENG | cut -d, -f9) + CHANNEL=$(echo $QENG | cut -d, -f10) + LBAND=$(echo $QENG | cut -d, -f11 | grep -o "[0-9]\{1,3\}") + BW=$(echo $QENG | cut -d, -f12) + lte_bw + BWU=$BW + BW=$(echo $QENG | cut -d, -f13) + lte_bw + BWD=$BW + if [ -z "$BWD" ]; then + BWD="unknown" + fi + if [ -z "$BWU" ]; then + BWU="unknown" + fi + if [ -n "$LBAND" ]; then + LBAND="B"$LBAND" (Bandwidth $BWD MHz Down | $BWU MHz Up)" + fi + RSRP=$(echo $QENG | cut -d, -f15 | grep -o "[0-9]\{1,3\}") + if [ -n "$RSRP" ]; then + RSCP="-"$RSRP + RSRPLTE=$RSCP + fi + RSRQ=$(echo $QENG | cut -d, -f16 | grep -o "[0-9]\{1,3\}") + if [ -n "$RSRQ" ]; then + ECIO="-"$RSRQ + fi + RSSI=$(echo $QENG | cut -d, -f17 | grep -o "\-[0-9]\{1,3\}") + if [ -n "$RSSI" ]; then + CSQ_RSSI=$RSSI" dBm" + fi + SINRR=$(echo $QENG | cut -d, -f18 | grep -o "[0-9]\{1,3\}") + if [ -n "$SINRR" ]; then + if [ $SINRR -le 25 ]; then + SINR=$((($(echo $SINRR) * 2) -20))" dB" + fi + fi + + if [ -n "$NR_NSA" ]; then + MODE="LTE/NR EN-DC" + echo "0" > /tmp/modnetwork + if [ -n "$QENG5" ] && [ -n "$LBAND" ] && [ "$RSCP" != "-" ] && [ "$ECIO" != "-" ]; then + PCI="$PCI, "$(echo $QENG5 | cut -d, -f4) + SCHV=$(echo $QENG5 | cut -d, -f8) + SLBV=$(echo $QENG5 | cut -d, -f9) + BW=$(echo $QENG5 | cut -d, -f10 | grep -o "[0-9]\{1,3\}") + if [ -n "$SLBV" ]; then + LBAND=$LBAND"
                                                                        n"$SLBV + if [ -n "$BW" ]; then + nr_bw + LBAND=$LBAND" (Bandwidth $BW MHz)" + fi + if [ "$SCHV" -ge 123400 ]; then + CHANNEL=$CHANNEL", "$SCHV + else + CHANNEL=$CHANNEL", -" + fi + else + LBAND=$LBAND"
                                                                        nxx (unknown NR5G band)" + CHANNEL=$CHANNEL", -" + fi + RSCP=$RSCP" dBm
                                                                        "$(echo $QENG5 | cut -d, -f5) + SINRR=$(echo $QENG5 | cut -d, -f6 | grep -o "[0-9]\{1,3\}") + if [ -n "$SINRR" ]; then + if [ $SINRR -le 30 ]; then + SINR=$SINR"
                                                                        "$((($(echo $SINRR) * 2) -20))" dB" + fi + fi + ECIO=$ECIO" (4G) dB
                                                                        "$(echo $QENG5 | cut -d, -f7)" (5G) " + fi + fi + if [ -z "$LBAND" ]; then + LBAND="-" + else + if [ -n "$QCA" ]; then + QCA=$(echo $QCA | grep -o "\"S[CS]\{2\}\"[-0-9A-Z,\"]\+") + for QCAL in $(echo "$QCA"); do + if [ $(echo "$QCAL" | cut -d, -f7) = "2" ]; then + SCHV=$(echo $QCAL | cut -d, -f2 | grep -o "[0-9]\+") + SRATP="B" + if [ -n "$SCHV" ]; then + CHANNEL="$CHANNEL, $SCHV" + if [ "$SCHV" -gt 123400 ]; then + SRATP="n" + fi + fi + SLBV=$(echo $QCAL | cut -d, -f6 | grep -o "[0-9]\{1,2\}") + if [ -n "$SLBV" ]; then + LBAND=$LBAND"
                                                                        "$SRATP$SLBV + BWD=$(echo $QCAL | cut -d, -f3 | grep -o "[0-9]\{1,3\}") + if [ -n "$BWD" ]; then + UPDOWN=$(echo $QCAL | cut -d, -f13) + case "$UPDOWN" in + "UL" ) + CATYPE="CA"$(printf "\xe2\x86\x91") ;; + "DL" ) + CATYPE="CA"$(printf "\xe2\x86\x93") ;; + * ) + CATYPE="CA" ;; + esac + if [ $BWD -gt 14 ]; then + LBAND=$LBAND" ("$CATYPE", Bandwidth "$(($(echo $BWD) / 5))" MHz)" + else + LBAND=$LBAND" ("$CATYPE", Bandwidth 1.4 MHz)" + fi + fi + LBAND=$LBAND + fi + PCI="$PCI, "$(echo $QCAL | cut -d, -f8) + fi + done + fi + fi + if [ $RAT = "CAT-M" ] || [ $RAT = "CAT-NB" ]; then + LBAND="B$(echo $QENG | cut -d, -f11) ($RAT)" + fi + ;; + "NR5G-SA") + MODE="NR5G-SA" + echo "0" > /tmp/modnetwork + if [ -n "$QENG5" ]; then + MODE="$RAT $(echo $QENG5 | cut -d, -f4)" + PCI=$(echo $QENG5 | cut -d, -f8) + CHANNEL=$(echo $QENG5 | cut -d, -f10) + LBAND=$(echo $QENG5 | cut -d, -f11) + BW=$(echo $QENG5 | cut -d, -f12) + nr_bw + LBAND="n"$LBAND" (Bandwidth $BW MHz)" + RSCP=$(echo $QENG5 | cut -d, -f13) + ECIO=$(echo $QENG5 | cut -d, -f14) + if [ "$CSQ_PER" = "-" ]; then + RSSI=$(rsrp2rssi $RSCP $BW) + CSQ_PER=$((100 - (($RSSI + 51) * 100/-62)))"%" + CSQ=$((($RSSI + 113) / 2)) + CSQ_RSSI=$RSSI" dBm" + fi + SINRR=$(echo $QENG5 | cut -d, -f15 | grep -o "[0-9]\{1,3\}") + if [ -n "$SINRR" ]; then + if [ $SINRR -le 30 ]; then + SINR=$((($(echo $SINRR) * 2) -20))" dB" + fi + fi + fi + ;; +esac + +QRSRP=$(echo "$OX" | grep -o "+QRSRP:[^,]\+,-[0-9]\{1,5\},-[0-9]\{1,5\},-[0-9]\{1,5\}[^ ]*") +if [ -n "$QRSRP" ] && [ "$RAT" != "WCDMA" ]; then + QRSRP1=$(echo $QRSRP | cut -d, -f1 | grep -o "[-0-9]\+") + QRSRP2=$(echo $QRSRP | cut -d, -f2) + QRSRP3=$(echo $QRSRP | cut -d, -f3) + QRSRP4=$(echo $QRSRP | cut -d, -f4) + QRSRPtype=$(echo $QRSRP | cut -d, -f5) + if [ "$QRSRPtype" == "NR5G" ]; then + if [ -n "$NR_SA" ]; then + RSCP=$QRSRP1 + if [ -n "$QRPRP2" -a "$QRSRP2" != "-32768" ]; then + RSCP1="RxD "$QRSRP2 + fi + if [ -n "$QRSRP3" -a "$QRSRP3" != "-32768" ]; then + RSCP=$RSCP" dBm
                                                                        "$QRSRP3 + fi + if [ -n "$QRSRP4" -a "$QRSRP4" != "-32768" ]; then + RSCP1="RxD "$QRSRP4 + fi + else + RSCP=$RSRPLTE + if [ -n "$QRSRP1" -a "$QRSRP1" != "-32768" ]; then + RSCP=$RSCP" (4G) dBm
                                                                        "$QRSRP1 + if [ -n "$QRSRP2" -a "$QRSRP2" != "-32768" ]; then + RSCP="$RSCP,$QRSRP2" + if [ -n "$QRSRP3" -a "$QRSRP3" != "-32768" ]; then + RSCP="$RSCP,$QRSRP3" + if [ -n "$QRSRP4" -a "$QRSRP4" != "-32768" ]; then + RSCP="$RSCP,$QRSRP4" + fi + fi + RSCP=$RSCP" (5G) " + fi + fi + fi + elif [ "$QRSRP2$QRSRP3$QRSRP4" != "-44-44-44" -a -z "$QENG5" ]; then + RSCP=$QRSRP1 + if [ "$QRSRP3$QRSRP4" == "-140-140" -o "$QRSRP3$QRSRP4" == "-44-44" -o "$QRSRP3$QRSRP4" == "-32768-32768" ]; then + RSCP1="RxD "$(echo $QRSRP | cut -d, -f2) + else + RSCP=$RSCP" dBm (RxD "$QRSRP2" dBm)
                                                                        "$QRSRP3 + RSCP1="RxD "$QRSRP4 + fi + fi +fi + +QNSM=$(echo "$QNSM" | grep -o "[0-9]") +if [ -n "$QNSM" ]; then + MODTYPE="6" + case $QNSM in + "0" ) + NETMODE="1" ;; + "1" ) + NETMODE="3" ;; + "2"|"5" ) + NETMODE="5" ;; + "3" ) + NETMODE="7" ;; + esac +fi +if [ -n "$QNWP" ]; then + MODTYPE="6" + case $QNWP in + "AUTO" ) + NETMODE="1" ;; + "WCDMA" ) + NETMODE="5" ;; + "LTE" ) + NETMODE="7" ;; + "LTE:NR5G" ) + NETMODE="8" ;; + "NR5G" ) + NETMODE="9" ;; + esac +fi + +CMODE=$(uci -q get modem.modem$CURRMODEM.cmode) +if [ "$CMODE" = 0 ]; then + NETMODE="10" +fi + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'PCI="'"$PCI"'"' + echo 'TEMP="'"$CTEMP"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/sierradata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/sierradata.sh new file mode 100644 index 0000000..11f1e99 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/sierradata.sh @@ -0,0 +1,258 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "Sierra Data" "$@" +} + +read_ssc() { + SLBAND=$(echo $OX | grep -o "LTE "$SSCx" BAND: B[0-9]\+ LTE "$SSCx" BW :") + SLBAND=$(echo $SLBAND | grep -o " BAND: B[0-9]\+ ") + if [ -n "$SLBAND" ]; then + SLBAND=$(echo $SLBAND | grep -o "[0-9]\+") + SLBAND=$(printf "
                                                                        B%d" $SLBAND) + BWD=$(echo $OX | grep -o " LTE "$SSCx" BW : [.012345]\+ [ML]") + BWD=$(echo $BWD | grep -o " BW : [.012345]\+" | grep -o "[.012345]\+") + if [ -n "$BWD" ]; then + SLBAND=$SLBAND$(printf " (CA, Bandwidth %s MHz)" $BWD) + else + SLBAND=$SLBAND$(printf " (CA, Bandwidth unknown)") + fi + LBAND=$LBAND$SLBAND + XTRACHAN=$(echo $OX | grep -o " LTE "$SSCx" CHAN: [0-9]\+") + XTRACHAN=$(echo "$XTRACHAN" | grep -o "[0-9]\{2,6\}") + if [ -n "$XTRACHAN" ]; then + CHANNEL=$(echo "$CHANNEL", "$XTRACHAN") + fi + fi +} + +CURRMODEM=$1 +COMMPORT=$2 + +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "sierrainfo.gcom" "$CURRMODEM") + +OX=$(echo $OX | tr 'a-z' 'A-Z') + +CSQ=$(echo $OX | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") +if [ -z "$CSQ" ] || [ "$CSQ" = "99" ]; then + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" +else + CSQ_PER=$(($CSQ * 100/31))"%" + CSQ_RSSI=$((2 * CSQ - 113))" dBm" +fi + +MODTYPE="-" +NETMODE="-" +LBAND="-" +PCI="-" + +LTEINFO=$(echo $OX | grep -o "!LTEINFO: .\+ INTRAFREQ:" | tr " " ",") +LTEINFO=$(echo "$LTEINFO" | grep -o "[0-9]\{1,6\}\,[0-9]\{3\}\,.\+") +if [ -n "$LTEINFO" ]; then + PCI=$(echo $LTEINFO | cut -d, -f10 | grep -o "[0-9]\{1,3\}") + if [ -z "$PCI" ]; then + PCI="-" + fi +fi + +SINR=$(echo $OX | grep -o "SINR (.B): [-.0-9]\{1,5\}" | tr '\n' ' ' | cut -d' ' -f3) +if [ -n "$SINR" ]; then + SINR5=$(echo $OX | grep -o "NR5G SINR (.B): [-]*[.0-9]\{1,5\}" | cut -d' ' -f4) + if [ -n "$SINR5" ]; then + SINR=$SINR" dB, "$SINR5 + fi + SINR=$SINR" dB" +else + SINR="-" +fi +TEMP=$(echo $OX | grep -o "TEMPERATURE: [-.0-9]\+ " | grep -o "[-.0-9]\+" | tr '\n' ' ') +if [ -n "$TEMP" ]; then + TEMP=$(printf "$(echo $TEMP | cut -d' ' -f2)\xc2\xb0C") +else + TEMP="unknown" +fi + +RAT=$(echo $OX | grep -o "SYSTEM MODE: [^ ]\{3,10\}" | cut -d' ' -f3) + +MODE=$RAT +case $RAT in + "WCDMA") + MODE=$(echo $OX | grep -o " \*CNTI: 0,[^ ]\+" | cut -d, -f2) + if [ -z "$MODE" ] || [ "$MODE" = "NONE" ]; then + MODE=$RAT + fi + CHANNEL=$(echo $OX | grep -o "WCDMA CHANNEL: [0-9]\{3,5\}" | cut -d' ' -f3) + if [ -n "$CHANNEL" ]; then + LOCKCHAN=$(echo $OX | grep -o "!UMTSCHAN? ENABLE: 01 CHANNEL: [0-9]\{3,5\}") + if [ -n "$LOCKCHAN" ]; then + LOCKCHAN=$(echo $LOCKCHAN | grep -o "CHANNEL: [0-9]\+" | grep -o "[0-9]\+") + CHANNEL=$CHANNEL" (Soft locked to $LOCKCHAN)" + fi + else + CHANNEL="-" + fi + ECIO=$(echo $OX | grep -o "EC/IO: [+-]\?[.0-9]\+") + ECIO=$(echo "$ECIO") + ECIO1=$(echo "$ECIO" | cut -d' ' -f4) + ECIO=$(echo "$ECIO" | cut -d' ' -f2) + RSCP=$(echo $OX | grep -o "RSCP: -[.0-9]\+") + RSCP=$(echo "$RSCP") + RSCP1=$(echo "$RSCP" | cut -d' ' -f4) + RSCP=$(echo "$RSCP" | cut -d' ' -f2) + ;; + "LTE") + LBAND=$(echo $OX | grep -o "LTE BAND: B[0-9]\+ LTE BW: [.012345]\+ MHZ" | grep -o "[.0-9]\+") + LBAND=$(printf "B%d (Bandwidth %s MHz)" $LBAND) + CHANNEL=$(echo $OX | grep -o "LTE RX CHAN: [0-9]\{1,6\}" | grep -o "[0-9]\+") + SLBAND=$(echo $OX | grep -o " ACTIVE LTE SCELL BAND:[ ]*B[0-9]\+ LTE SCELL BW:[ ]*[.012345]\+ MHZ") + if [ -n "$SLBAND" ]; then + SLBAND=$(echo $SLBAND | grep -o "[.0-9]\+") + SLBAND=$(printf "
                                                                        B%d (CA, Bandwidth %s MHz)" $SLBAND) + LBAND=$LBAND$SLBAND + XTRACHAN=$(echo $OX | grep -o " LTE SCELL CHAN:[0-9]\+" | grep -o "[0-9]\{2,6\}") + CHANNEL=$CHANNEL", "$XTRACHAN + fi + SSCLIST=$(echo $OX | grep -o "LTE S[CS]C[0-9] STATE:[ ]\?ACTIVE" | grep -o "[0-9]") + for SSCVAL in $(echo "$SSCLIST"); do + SSCx="S[CS]C"$SSCVAL + read_ssc + done + if [ -n "$LTEINFO" ]; then + RSCP=$(echo $LTEINFO | cut -d, -f12 | grep -o "[-][.0-9]\{2,5\}") + ECIO=$(echo $LTEINFO | cut -d, -f11 | grep -o "[-.0-9]\{1,5\}") + fi + if [ -z "$RSCP" ]; then + RSCP=$(echo $OX | grep -o "PCC RXM RSRP: -[0-9]\{2,3\} " | cut -d' ' -f4) + fi + if [ -n "$RSCP" ]; then + RSCP1=$(echo $OX | grep -o "PCC RXD RSRP: -[0-9]\{2,3\} " | cut -d' ' -f4) + if [ -z "$RSCP1" ]; then + RSCP1=$(echo $OX | grep -o "PCC RXD RSSI: -[0-9]\+ RSRP (DBM): -[0-9]\{2,3\} " | cut -d' ' -f7) + fi + else + RSCP=$(echo $OX | grep -o "RSRP (DBM): -[0-9]\{2,3\} " | tr '\n' ' ' | cut -d' ' -f3) + fi + if [ -z "$ECIO" ]; then + ECIO=$(echo $OX | grep -o "RSRQ (DB): [-.0-9]\{1,5\} " | cut -d' ' -f3) + fi + ;; + "ENDC") + MODE="LTE/NR EN-DC" + LBAND=$(echo $OX | grep -o "LTE BAND: B[0-9]\+ LTE BW: [.012345]\+ MHZ" | grep -o "[.0-9]\+") + LBAND=$(printf "B%d (Bandwidth %s MHz)" $LBAND) + CHANNEL=$(echo $OX | grep -o "LTE RX CHAN: [0-9]\{1,6\}" | grep -o "[0-9]\+") + NBAND=$(echo $OX | grep -o "NR5G BAND: N[0-9]\+ NR5G BW: [0-9]\+ MHZ") + NBAND=$(echo "$NBAND" | cut -d' ' -f3)" "$(echo "$NBAND" | cut -d' ' -f6) + if [ "$NBAND" != " " ]; then + NBAND=$(echo $NBAND | grep -o "[.0-9]\+") + NBAND=$(printf "
                                                                        n%d (Bandwidth %s MHz)" $NBAND) + LBAND=$LBAND$NBAND + NCHAN=$(echo $OX | grep -o "NR5G RX CHAN: [0-9]\{6\}" | cut -d' ' -f4) + CHANNEL=$CHANNEL", "$NCHAN + fi + SSCLIST=$(echo $OX | grep -o "LTE S[CS]C[0-9] STATE:[ ]\?ACTIVE" | grep -o "[0-9]") + for SSCVAL in $(echo "$SSCLIST"); do + SSCx="S[CS]C"$SSCVAL + read_ssc + done + RSCP=$(echo $OX | grep -o "PCC RXM RSRP: -[0-9]\{2,3\} " | cut -d' ' -f4) + RSCP1=$(echo $OX | grep -o "NR5G RSRP (DBM): -[0-9]\{2,3\} " | cut -d' ' -f4) + ECIO=$(echo $OX | grep -o "RSRQ (DB): [-.0-9]\{1,5\} " | tr '\n' ' ' | cut -d' ' -f3) + ECIO1=$(echo $OX | grep -o "NR5G RSRQ (DB): [-.0-9]\{1,5\} " | cut -d' ' -f4) + ;; + "NR5G") + MODE="NR5G-SA" + NBAND=$(echo $OX | grep -o "NR5G BAND: N[0-9]\+ NR5G BW: [0-9]\+ MHZ") + NBAND=$(echo "$NBAND" | cut -d' ' -f3)" "$(echo "$NBAND" | cut -d' ' -f6) + CHANNEL=$(echo $OX | grep -o "NR5G RX CHAN: [0-9]\{1,6\}" | grep -o "[0-9]\+") + RSCP=$(echo $OX | grep -o "PCC RXM RSRP: -[0-9]\{2,3\} " | cut -d' ' -f4) + ECIO=$(echo $OX | grep -o "RSRQ (DB): [-.0-9]\{1,5\} " | cut -d' ' -f3) + ;; +esac + +SELRAT=$(echo $OX | grep -o "!SELRAT:[^0-9]\+[0-9]\{2\}" | grep -o "[0-9]\{2\}") +if [ -n "$SELRAT" ]; then + MODTYPE="2" + case $SELRAT in + "01" ) + NETMODE="5" + ;; + "02" ) + NETMODE="3" + ;; + "06" ) + NETMODE="7" + ;; + * ) + NETMODE="1" + ;; + esac +fi + +CMODE=$(uci -q get modem.modem$CURRMODEM.cmode) + +if [ "$CMODE" = 0 ]; then + NETMODE="10" +fi +if [ -z "$RSCP1" ]; then + RSCP1=" " +fi +if [ -z "$ECIO1" ]; then + ECIO1=" " +fi + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'PCI="'"$PCI"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +CONNECT=$(uci -q get modem.modem$CURRMODEM.connected) + +if [ "$CONNECT" -eq 0 ]; then + exit 0 +fi + +if [ $CSQ = "-" ]; then + log "$OX" +fi + +ENB="0" +if [ -e /etc/config/failover ]; then + ENB=$(uci get failover.enabled.enabled) +fi + +if [ $ENB = "1" ]; then + exit 0 +fi + +WWANX=$(uci -q get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/simcomdata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/simcomdata.sh new file mode 100644 index 0000000..e48fdaf --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/simcomdata.sh @@ -0,0 +1,172 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +CURRMODEM=$1 +COMMPORT=$2 + +decode_bw() { + BW=$(echo $BW | grep -o "[0-5]\{1\}") + case $BW in + "0") + BW="1.4" ;; + "1") + BW="3" ;; + "2") + BW="5" ;; + "3") + BW="10" ;; + "4") + BW="15" ;; + "5") + BW="20" ;; + esac +} + +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "simcominfo.gcom" "$CURRMODEM") + +OX=$(echo $OX | tr 'a-z' 'A-Z') + +REGXa="+CPSI:[ ]*LTE,ONLINE,[0-9]\{3\}-[0-9]\{2,3\},0X[0-9A-F]\{1,5\},[0-9]\{3,9\},[0-9]\{1,3\},[-A-Z0-9]\+,[0-9]\{1,6\},[0-5],[0-5],-[0-9]\{1,3\},-[0-9]\{1,4\},[-0-9]\{1,5\},[0-9]\{1,2\}" + +REGXb="+CPSI:[ ]*NR5G[_ANS]*,[0-9]\{1,3\},[0-9]\{6\},-[0-9]\{1,4\},-[0-9]\{1,4\},[-0-9]\{1,4\}" + +REGXc="+CPSI:[ ]*NR5G_SA,ONLINE,[0-9]\{3\}-[0-9]\{2,3\},0X[0-9A-F]\{1,6\},[0-9]\{3,13\},[0-9]\{1,3\},[^,]\+,[0-9]\{6,7\},-[0-9]\{1,4\},-[0-9]\{1,4\},[-0-9]\{1,4\}" + +REGXz="+CMGRMI: CA_SCELL,[0-9]\{2,6\},[^,]\+,[0-9]\{1,3\},[0-5],[^,]\+,[0-9]\{1,3\},[^,]\+,[^,]\+,[^,]\+,[^,]\+,[^,]\+,1" + +CHANNEL="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +NETMODE="-" +LBAND="-" +PCI="-" +CTEMP="-" +MODE="" +SINR="-" + +CSQ=$(echo "$OX" | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") +if [ $CSQ = "99" ]; then + CSQ="" +fi +if [ -n "$CSQ" ]; then + CSQ_PER=$(($CSQ * 100/31))"%" + CSQ_RSSI=$((2 * CSQ - 113))" dBm" +else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" +fi + +CPSIa=$(echo "$OX" | grep -o "$REGXa") +if [ -n "$CPSIa" ]; then + CPSIb=$(echo "$OX" | grep -o "$REGXb") + PCI=$(echo $CPSIa | cut -d, -f6) + LBAND=$(echo $CPSIa | cut -d, -f7 | grep -o "[0-9]\{1,3\}") + CHANNEL=$(echo $CPSIa | cut -d, -f8) + BW=$(echo $CPSIa | cut -d, -f9) + decode_bw + BWD=$BW + BW=$(echo $CPSIa | cut -d, -f10) + decode_bw + BWU=$BW + LBAND="B"$LBAND" (Bandwidth $BWD MHz Down | $BWU MHz Up)" + ECIO=$(($(echo $CPSIa | cut -d, -f11) / 10)) + RSCP=$(($(echo $CPSIa | cut -d, -f12) / 10)) + SINR=$((($(echo $CPSIa | cut -d, -f14) * 2) - 20))" dB" + if [ -n "$CPSIb" ]; then + MODE="LTE/NR EN-DC" + PCI=$PCI", "$(echo $CPSIb | cut -d, -f2) + NCHAN=$(echo $CPSIb | cut -d, -f3) + CHANNEL="$CHANNEL, $NCHAN" + NBAND=$("$ROOTER/chan2band.sh" "$NCHAN") + if [ "$NBAND" = "-" ]; then + LBAND=$LBAND"
                                                                        nxx (unknown NR5G band)" + else + LBAND=$LBAND"
                                                                        "$NBAND + fi + RSCP=$RSCP" dBm
                                                                        "$(($(echo $CPSIb | cut -d, -f4) / 10)) + ECIO=$ECIO" dB
                                                                        "$(($(echo $CPSIb | cut -d, -f5) / 10)) + SSINR=$(echo $CPSIb | cut -d, -f6) + if [ $SSINR -lt 255 ]; then + SINR=$SINR"
                                                                        "$((($SSINR / 5) - 20))" dB" + fi + else + MODE="LTE" + fi + CPSIc="" +else + CPSIc=$(echo "$OX" | grep -o "$REGXc") + if [ -n "$CPSIc" ]; then + MODE="NR5G" + PCI=$(echo $CPSIc | cut -d, -f6) + LBAND="n"$(echo $CPSIc | cut -d, -f7 | grep -o "BAND[0-9]\{1,3\}" | grep -o "[0-9]\+") + CHANNEL=$(echo $CPSIc | cut -d, -f8) + RSCP=$(($(echo $CPSIc | cut -d, -f9) / 10)) + ECIO=$(($(echo $CPSIc | cut -d, -f10) / 10)) + if [ "$CSQ_PER" = "-" ]; then + CSQ_PER=$((100 - (($RSCP + 31) * 100/-125)))"%" + fi + SINR=$(($(echo $CPSIc | cut -d, -f11) / 10))" dB" + fi + CPSIb="" +fi + +CAINFO=$(echo "$OX" | grep -o "$REGXz" | tr ' ' ':') +if [ -n "$CAINFO" ]; then + for CASV in $(echo "$CAINFO"); do + LBAND=$LBAND"
                                                                        B"$(echo "$CASV" | cut -d, -f4) + BW=$(echo "$CASV" | cut -d, -f5) + decode_bw + LBAND=$LBAND" (CA, Bandwidth $BW MHz)" + CHANNEL="$CHANNEL, "$(echo "$CASV" | cut -d, -f2) + PCI="$PCI, "$(echo "$CASV" | cut -d, -f7) + done +fi + +CNMP=$(echo "$OX" | grep -o "+CNMP:[ ]*[0-9]\{1,3\}" | grep -o "[0-9]\{1,3\}") +TEMP=$(echo "$OX" | grep -o "+CPMUTEMP:[ ]*[-0-9]\+" | grep -o "[-0-9]\{1,4\}") + +if [ -n "$CNMP" ]; then + case $CNMP in + "2"|"55" ) + NETMODE="1" ;; + "13" ) + NETMODE="3" ;; + "14" ) + NETMODE="5" ;; + "38" ) + NETMODE="7" ;; + "71" ) + NETMODE="9" ;; + "109" ) + NETMODE="8" ;; + * ) + NETMODE="0" ;; + esac +fi +if [ -n "$TEMP" ]; then + TEMP=$(echo $TEMP)$(printf "\xc2\xb0")"C" +fi +MODTYPE="10" + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'PCI="'"$PCI"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/t77data.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/t77data.sh new file mode 100644 index 0000000..5c7ad2e --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/t77data.sh @@ -0,0 +1,236 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "T77 Data" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "t77info.gcom" "$CURRMODEM") + +OX=$(echo $OX | tr 'a-z' 'A-Z') +O=$($ROOTER/common/processat.sh "$OX") +O=$(echo $O) + +REGXca="BAND:[0-9]\{1,3\} BW:[0-9.]\+MHZ EARFCN:[0-9]\+ PCI:[0-9]\+ RSRP:[^R]\+RSRQ:[^R]\+RSSI:[^S]\+SNR[^D]\+" +REGXrxd="RX_DIVERSITY:[^(]\+([^)]\+" + +RSRP="" +RSRQ="" +CHANNEL="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +MODTYPE="-" +NETMODE="-" +LBAND="-" +PCI="-" +SINR="-" + +CSQ=$(echo $OX | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") +if [ "$CSQ" = "99" ]; then + CSQ="" +fi +if [ -n "$CSQ" ]; then + CSQ_PER=$(($CSQ * 100/31))"%" + CSQ_RSSI=$((2 * CSQ - 113))" dBm" +else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" +fi + +TEMP=$(echo $OX | grep -o "TSENS_TZ_SENSOR[0-9]:[0-9]\{1,3\}") +if [ -n "$TEMP" ]; then + TEMP=${TEMP:17:3} +fi +if [ -z "$TEMP" ]; then + TEMP=$(echo $OX | grep -o "XO_THERM_BUF:[0-9]\{1,3\}") + if [ -n "$TEMP" ]; then + TEMP=${TEMP:13:3} + fi +fi +if [ -z "$TEMP" ]; then + TEMP=$(echo $OX | grep -o "TSENS: [0-9]\{1,3\}C") +fi +if [ -n "$TEMP" ]; then + TEMP=$(echo $TEMP | grep -o "[0-9]\{1,3\}")$(printf "\xc2\xb0")"C" +else + TEMP="-" +fi +TECH=$(echo $O" " | grep -o "+COPS: .,.,[^,]\+,[027]") +TECH="${TECH: -1}" + +if [ -n "$TECH" ]; then + RSSI=$(echo $O | grep -o " RSSI: [^D]\+D" | grep -o "[-0-9\.]\+") + if [ -n "$RSSI" ]; then + CSQ_RSSI=$(echo $RSSI)" dBm" + fi + case $TECH in + "7") + MODE="LTE" + ECIO=$(echo $O | grep -o " RSRQ: [^D]\+D" | grep -o "[-0-9\.]\+") + SINR=$(echo $OX | grep -o "RS-S[I]*NR: [^D]\+D") + SINR=${SINR:8} + SINR=$(echo "$SINR" | grep -o "[-0-9.]\{1,3\}")" dB" + LBAND="B"$(echo $O | grep -o " BAND: [0-9]\+" | grep -o "[0-9]\+") + DEBUGv1=$(echo $O | grep -o "EARFCN(DL/UL):") + DEBUGv2=$(echo $O | grep -o "LTE ENGINEERING") + if [ -n "$DEBUGv1" ]; then + RSCP=$(echo $O | grep -o "[^G] RSRP: [^D]\+D" | grep -o "[-0-9\.]\+") + RSRPlist=$(echo $OX | grep -o "$REGXrxd" | grep -o "\-[.0-9]\{4,5\}" | tr "\n" ",") + if [ -n "$RSRPlist" ]; then + RSCP=$(echo $RSRPlist | cut -d, -f1) + MIMO=$(echo $OX | grep -o "$REGXrxd" | cut -d" " -f2) + if [ "$MIMO" == "3" ]; then + RSCP="(2xMIMO) $RSCP" + fi + for IDX in 2 3 4; do + RSCPval=$(echo $RSRPlist | cut -d, -f$IDX) + if [ -n "$RSCPval" -a "$RSCPval" != "-256.0" ]; then + RSCP="$RSCP dBm, $RSCPval" + fi + done + fi + CHANNEL=$(echo $O | grep -o " EARFCN(DL/UL): [0-9]\+" | grep -o "[0-9]\+") + BWD=$(echo $O | grep -o " BW: [0-9\.]\+ MHZ" | grep -o "[0-9\.]\+") + if [ "$BWD" != "1.4" ]; then + BWD=${BWD/.*} + fi + LBAND=$LBAND" (Bandwidth $BWD MHz)" + PCI=$(echo $OX | grep -o " ENB ID(PCI): [^(]\+([0-9]\{1,3\})" | grep -o "([0-9]\+)" | grep -o "[0-9]\+") + fi + if [ -n "$DEBUGv2" ]; then + RSCP=$(echo $O | grep -o "RSRP: [^D]\+D" | grep -o "[-0-9\.]\+") + CHANNEL=$(echo $O | grep -o " DL CHANNEL: [0-9]\+" | grep -o "[0-9]\+") + PCI=$(echo $OX | grep -o " PCI: [0-9]\{1,3\}" | grep -o "[0-9]\+") + fi + SCC=$(echo $OX | grep -o " SCELL[1-9]:") + if [ -n "$SCC" ]; then + SCCn=$(echo $SCC | grep -o [0-9]) + for SCCx in $(echo "$SCCn"); do + SCCv=$(echo $OX | grep -o "SCELL$SCCx: $REGXca" | tr ' ' ',') + if [ -n "$SCCv" ]; then + SLBV=B$(echo $SCCv | cut -d, -f2 | grep -o "[0-9]\{1,3\}") + SBWV=$(echo $SCCv | cut -d, -f3 | grep -o "[0-9][^M]\+") + if [ "$SBWV" != "1.4" ]; then + SBWV=${SBWV%.*} + fi + LBAND=$LBAND"
                                                                        "$SLBV" (CA, Bandwidth "$SBWV" MHz)" + CHANNEL=$CHANNEL", "$(echo $SCCv | cut -d, -f4 | grep -o "[0-9]\+") + PCI=$PCI", "$(echo $SCCv | cut -d, -f5 | grep -o "[0-9]\+") + RSCP=$RSCP" dBm, "$(echo $SCCv | cut -d, -f6 | grep -o "[-0-9.]\+") + ECIO=$ECIO" dB, "$(echo $SCCv | cut -d, -f7 | grep -o "[-0-9.]\+") + CSQ_RSSI=$CSQ_RSSI", "$(echo $SCCv | cut -d, -f8 | grep -o "[-0-9.]\+")" dBm" + SINR=$SINR", "$(echo $SCCv | cut -d, -f9 | grep -o "[-0-9.]\+")" dB" + fi + done + else + SCC=$(echo $O | grep -o " SCC[1-9][^M]\+MHZ") + if [ -n "$SCC" ]; then + printf '%s\n' "$SCC" | while read SCCX; do + SCCX=$(echo $SCCX | tr " " ",") + SLBV=$(echo $SCCX | cut -d, -f5 | grep -o "B[0-9]\{1,3\}") + SBWV=$(echo $SCCX | cut -d, -f9) + if [ "$SBWV" != "1.4" ]; then + SBWV=${SBWV/.*} + fi + LBAND=$LBAND"
                                                                        "$SLBV" (CA, Bandwidth "$SBWV" MHz)" + echo "$LBAND" > /tmp/lbandvar$CURRMODEM + done + if [ -e /tmp/lbandvar$CURRMODEM ]; then + read LBAND < /tmp/lbandvar$CURRMODEM + rm /tmp/lbandvar$CURRMODEM + fi + fi + fi + ;; + "2") + MODE="WCDMA" + DEBUGv1=$(echo $O | grep -o "RAT:WCDMA") + if [ -n "$DEBUGv1" ]; then + RSCP=$(echo $O | grep -o "RSCP:[^)]\+" | grep -o "[-0-9\.]\+DBM," | grep -o "[^DBM,]\+") + ECIO=$(echo $O | grep -o " ECIO:[^D]\+D" | grep -o "[-0-9\.]\+") + ECIO=$(echo $ECIO) + CHANNEL=$(echo $O | grep -o " CHANNEL (DL): [0-9]\+" | grep -o "[0-9]\+") + LBAND="B"$(echo $O | grep -o " BAND: [0-9]\+" | grep -o "[0-9]\+") + BW=$(echo $O | grep -o " BW: [0-9\.]\+ MHZ" | grep -o "[0-9\.]\+") + BW=$(printf "%.0f" $BW ) + LBAND=$LBAND" (Bandwidth $BW MHz)" + PCI=$(echo $OX | grep -o "PSC:.\?[0-9]\{1,3\}" | grep -o "[0-9]\+") + else + QCSQ=$(echo $O | grep -o "\$QCSQ: -[0-9]\{2,3\},[-0-9]\{1,3\},[-0-9]\{1,3\},") + if [ -n "$QCSQ" ]; then + RSCP=$(echo $QCSQ | cut -d, -f1 | grep -o "[-0-9]*") + ECIO=$(echo $QCSQ | cut -d, -f2) + fi + fi + ;; + *) + MODE="GSM" + ;; + esac +fi + +SCFG=$(echo $OX | grep -o "\^SYSCONFIG: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") +if [ -n "$SCFG" ]; then + case $SCFG in + "13" ) + NETMODE="3" ;; + "14" ) + NETMODE="5" ;; + "17" ) + NETMODE="7" ;; + * ) + NETMODE="1" ;; + esac +fi + +MODTYPE="8" + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'PCI="'"$PCI"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +CONNECT=$(uci get modem.modem$CURRMODEM.connected) +if [ $CONNECT -eq 0 ]; then + exit 0 +fi + +if [ "$CSQ" = "-" ]; then + log "$OX" +fi + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/telitdata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/telitdata.sh new file mode 100644 index 0000000..8b677f5 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/telitdata.sh @@ -0,0 +1,241 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +CURRMODEM=$1 +COMMPORT=$2 + +log() { + logger -t "Telit Data" "$@" +} +decode_bw() { + case $BW in + "0") + BW="1.4" + ;; + "1") + BW="3" + ;; + "2") + BW="5" + ;; + "3") + BW="10" + ;; + "4") + BW="15" + ;; + "5") + BW="20" + ;; + *) + BW="" + ;; + esac +} +decode_band() { + if [ "$SLBV" -lt 134 ]; then + SLBV=$(($SLBV - 119)) + elif [ "$SLBV" -eq 134 ]; then + SLBV="17" + elif [ "$SLBV" -lt 143 ]; then + SLBV=$(($SLBV - 102)) + elif [ "$SLBV" -lt 147 ]; then + SLBV=$(($SLBV - 125)) + elif [ "$SLBV" -lt 149 ]; then + SLBV=$(($SLBV - 123)) + elif [ "$SLBV" -lt 152 ]; then + SLBV=$(($SLBV - 108)) + elif [ "$SLBV" -eq 152 ]; then + SLBV="23" + elif [ "$SLBV" -eq 153 ]; then + SLBV="26" + elif [ "$SLBV" -eq 154 ]; then + SLBV="32" + elif [ "$SLBV" -lt 158 ]; then + SLBV=$(($SLBV - 30)) + elif [ "$SLBV" -lt 161 ]; then + SLBV=$(($SLBV - 130)) + elif [ "$SLBV" -eq 161 ]; then + SLBV="66" + elif [ "$SLBV" -eq 162 ]; then + SLBV="250" + elif [ "$SLBV" -eq 163 ]; then + SLBV="46" + elif [ "$SLBV" -eq 166 ]; then + SLBV="71" + else + SLBV="??" + fi + +} + +idV=$(uci get modem.modem$CURRMODEM.idV) +idP=$(uci get modem.modem$CURRMODEM.idP) + +if [ $idP = 1040 -o $idP = 1041 ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "telitinfo.gcom" "$CURRMODEM" | tr 'a-z' 'A-Z') +else + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "telitinfoln.gcom" "$CURRMODEM" | tr 'a-z' 'A-Z') +fi + +O=$($ROOTER/common/processat.sh "$OX") +O=$(echo $O) + +RSRP="" +RSRQ="" +CHANNEL="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +MODTYPE="-" +NETMODE="-" +LBAND="-" +TEMP="-" +PCI="-" +SINR="-" + +CSQ=$(echo $O | grep -o "CSQ: [0-9]\+" | grep -o "[0-9]\+") +[ "x$CSQ" = "x" ] && CSQ=-1 + +if [ $CSQ -ge 0 -a $CSQ -le 31 ]; then + CSQ_PER=$(($CSQ * 100/31)) + CSQ_RSSI=$((2 * CSQ - 113)) + CSQX=$CSQ_RSSI + [ $CSQ -eq 0 ] && CSQ_RSSI="<= "$CSQ_RSSI + [ $CSQ -eq 31 ] && CSQ_RSSI=">= "$CSQ_RSSI + CSQ_PER=$CSQ_PER"%" + CSQ_RSSI=$CSQ_RSSI" dBm" +else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" +fi + +TMP=$(echo $O" " | grep -o "#TEMPSENS: .\+ OK " | tr " " ",") +if [ -n "$TMP" ]; then + TEMP=$(echo $TMP | cut -d, -f3)$(printf "\xc2\xb0")"C" +fi + +MODE="-" +WS46=$(echo $O | grep -o "+COPS:.\+AT#RFSTS" | grep -o "+COPS: [0-3],[0-3],\"[^\"].\+\",[027]") +TECH=$(echo $WS46 | cut -d, -f4) +if [ -n "$TECH" ]; then + MODE=$TECH + case $MODE in + "7") + MODE="LTE" + CAINFO=$(echo $OX | grep -o "#CAINFO: 1.\+OK") + SGCELL=$(echo $OX | grep -o "[#^]RFSTS: \"[ 0-9]\{5,7\}\",[0-9]\{1,5\},.\+,\"[0-9]\{15\}\",\"[^\"]*\",[0-3],[0-9]\{1,2\}[,0-9]\{0,4\}") + if [ -n "$SGCELL" ]; then + RSCP=$(echo $SGCELL | cut -d, -f3) + ECIO=$(echo $SGCELL | cut -d, -f5) + RSSI=$(echo $SGCELL | cut -d, -f4) + CSQ_RSSI=$(echo "$RSSI dBm") + CHANNEL=$(echo $SGCELL | cut -d, -f2) + if [ $(echo ${SGCELL:0:1}) = "#" ]; then + LBAND="B"$(echo $SGCELL | cut -d, -f16 | grep -o "[0-9]\{1,2\}") + else + LBAND="B"$(echo $SGCELL | cut -d, -f15) + SSINR=$(echo $SGCELL | cut -d, -f16) + if [ -n "$SSINR" ]; then + SINR=$((($(echo $SSINR) / 5) - 20))" dB" + fi + fi + BW=$(echo $CAINFO | cut -d, -f3) + decode_bw + if [ -n "$BW" ];then + LBAND=$LBAND" (Bandwidth $BW MHz)" + fi + if [ -n "$CAINFO" ]; then + SCCLIST=$(echo $CAINFO | grep -o "1[2-6][0-9],[0-9]\{1,5\},[0-5],[0-9]\{1,3\},-[0-9]\+,-[0-9]\+,-[0-9]\+,[0-9]\{1,3\},2,[0-5],") + if [ -n "$SCCLIST" ]; then + SSINR=$(echo $CAINFO | grep -o "#CAINFO: [^,]\+,[^,]\+,[^,]\+,[^,]\+,[^,]\+,[^,]\+,[^,]\+,[0-9]\{1,3\},") + SINR=$((($(echo $SSINR | cut -d, -f8) / 5) - 20))" dB" + printf '%s\n' "$SCCLIST" | while read SCCVAL; do + PCI=$(echo $SCCVAL | cut -d, -f4) + SLBV=$(echo $SCCVAL | cut -d, -f1) + decode_band + LBAND=$LBAND"
                                                                        B"$SLBV + BW=$(echo $SCCVAL | cut -d, -f3) + decode_bw + LBAND=$LBAND" (CA, Bandwidth $BW MHz)" + SCHV=$(echo $SCCVAL | cut -d, -f2) + CHANNEL=$(echo "$CHANNEL", "$SCHV") + { + echo "$LBAND" + echo "$CHANNEL" + } > /tmp/lbandvar$CURRMODEM + done + fi + fi + if [ -e /tmp/lbandvar$CURRMODEM ]; then + { + read LBAND + read CHANNEL + } < /tmp/lbandvar$CURRMODEM + rm /tmp/lbandvar$CURRMODEM + fi + fi + ;; + 2) + MODE="UMTS" + SGCELL=$(echo $O | grep -o "[#^]RFSTS: \"[ 0-9]\{5,7\}\",[0-9]\{1,5\},.\+,\"[0-9]\{15\}\",") + if [ -n "$SGCELL" ]; then + RSSI=$(echo $SGCELL | cut -d, -f6) + CSQ_RSSI=$(echo "$RSSI dBm") + RSCP=$(echo $SGCELL | cut -d, -f5) + ECIO=$(echo $SGCELL| cut -d, -f4) + CHANNEL=$(echo $SGCELL | cut -d, -f2) + fi + ;; + esac +fi + +NETMODE="1" +MODTYPE="8" + +{ + echo 'CSQ="'"$CSQ"'"' + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'PCI="'"$PCI"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +CONNECT=$(uci get modem.modem$CURRMODEM.connected) + +if [ $CONNECT -eq 0 ]; then + exit 0 +fi + +if [ "$CSQ" = "-" ]; then + log "$OX" +fi + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/ubloxdata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/ubloxdata.sh new file mode 100644 index 0000000..6f9a4ec --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/ubloxdata.sh @@ -0,0 +1,250 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "ublox Data" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +get_ublox() { + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "ubloxinfo.gcom" "$CURRMODEM" | tr 'a-z' 'A-Z') +} + +get_ublox + +UCGED=$(echo $OX | grep -o "+UCGED: 2") +if [ -z "$UCGED" ]; then + ATCMDD="AT+UCGED=2" + UCGED=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + get_ublox +fi +OX=$(echo $OX) + +RSRP="" +RSRQ="" +CHANNEL="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +MODTYPE="-" +NETMODE="-" +LBAND="-" +TEMP="-" +PCI="-" +SINR="-" + +CSQ=$(echo $OX | grep -o "+CSQ: .\+ +CESQ" | tr " " ",") +CESQ=$(echo $OX | grep -o "+CESQ: .\+ +URAT" | tr " " ",") +URAT=$(echo $OX | grep -o "+URAT: .\+ +UCGED" | tr " " ",") +UCGED=$(echo $OX" " | grep -o "+UCGED: .\+ OK " | tr " " ",") + +CSQ=$(echo $CSQ | cut -d, -f2) +CSQ=$(echo $CSQ | grep -o "[0-9]\{1,2\}") + +if [ "$CSQ" -eq "99" ]; then + CSQ="" +fi +if [ -n "$CSQ" ]; then + CSQ_PER=$(($CSQ * 100/31))"%" + CSQ_RSSI=$((2 * CSQ - 113))" dBm" +else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" +fi + +RAT=$(echo $UCGED | cut -d, -f3) +case "$RAT" in + "2") + MODE="GSM" + LAC=$(echo $UCGED | cut -d, -f11) + LAC=$(echo $LAC | grep -o "[0-9A-F]\{4\}") + CID=$(echo $UCGED | cut -d, -f9) + CID=$(echo $CID | grep -o "[0-9A-F]\{4\}") + ;; + "3") + MODE="UMTS" + CHANNEL=$(echo $UCGED | cut -d, -f7) + LAC=$(echo $UCGED | cut -d, -f10) + LAC=$(echo $LAC | grep -o "[0-9A-F]\{4\}") + CID=$(echo $UCGED | cut -d, -f9) + CID=$(echo $CID | grep -o "[0-9A-F]\{5,8\}") + RSCP=$(echo $CESQ | cut -d, -f4) + RSCP=$(echo $RSCP | grep -o "[0-9]\{1,3\}") + if [ "$RSCP" -eq "255" ]; then + RSCP="" + fi + if [ -n "$RSCP" ]; then + RSCP=$(($RSCP - 121)) + fi + ECIO=$(echo $CESQ | cut -d, -f5) + ECIO=$(echo $ECIO | grep -o "[0-9]\{1,3\}") + if [ "$ECIO" -eq "255" ]; then + ECIO="" + fi + if [ -n "$ECIO" ]; then + ECIO=$((($ECIO / 2) - 24)) + fi + ;; + "4") + MODE="LTE" + LBAND=$(echo $UCGED | cut -d, -f8) + if [ "$LBAND" -eq "255" ]; then + LBAND="" + fi + BWU=$(echo $UCGED | cut -d, -f9) + BWU=$(echo $BWU | grep -o "[0-9]\{1,3\}") + BWD=$(echo $UCGED | cut -d, -f10) + BWD=$(echo $BWD | grep -o "[0-9]\{1,3\}") + if [ -z "$BWD" ]; then + LBAND="" + fi + if [ -z "$BWU" ]; then + LBAND="" + fi + if [ -z "$LBAND" ]; then + LBAND="-" + else + if [ "$BWU" = "6" ]; then + BWU="1.4" + else + BWU=$(($(echo $BWU) / 5)) + fi + if [ "$BWD" = "6" ]; then + BWD="1.4" + else + BWD=$(($(echo $BWD) / 5)) + fi + LBAND="B"$LBAND" (Bandwidth $BWD MHz Down | $BWU MHz Up)" + fi + LAC=$(echo $UCGED | cut -d, -f11) + LAC=$(echo $LAC | grep -o "[0-9A-F]\{4\}") + CID=$(echo $UCGED | cut -d, -f12) + CID=$(echo $CID | grep -o "[0-9A-F]\{5,8\}") + RSRP=$(echo $CESQ | cut -d, -f7) + RSRP=$(echo $RSRP | grep -o "[0-9]\{1,3\}") + if [ "$RSRP" -eq "255" ]; then + RSRP="" + fi + if [ -n "$RSRP" ]; then + RSRP=$(($RSRP - 141)) + RSCP=$RSRP + fi + RSRQ=$(echo $CESQ | cut -d, -f6) + RSRQ=$(echo $RSRQ | grep -o "[0-9]\{1,3\}") + if [ "$RSRQ" -eq "255" ]; then + RSRQ="" + fi + if [ -n "$RSRQ" ]; then + RSRQ=$((($RSRQ / 2) - 19)) + ECIO=$RSRQ + fi + ;; +esac + +if [ $RAT -eq "2" ]; then + if [ -n "$CID" ]; then + CID_NUM=$(printf "%d" 0x$CID) + CID=$CID" ("$CID_NUM")" + fi +else + CID=$(echo $CID | grep -o "[0-9A-F]\{5,8\}") + if [ -n "$CID" ]; then + LCID=$(printf "%08X" 0x$CID) + LCID_NUM=$(printf "%d" 0x$LCID) + if [ "$RAT" -eq "4" ]; then + RNC=$(printf "${LCID:1:5}") + CID=$(printf "${LCID:6:2}") + else + RNC=$(printf "${LCID:1:3}") + CID=$(printf "${LCID:4:4}") + fi + CID_NUM=$(printf "%d" 0x$CID) + CID=$CID" ("$CID_NUM")" + RNC_NUM=" ("$(printf "%d" 0x$RNC)")" + fi +fi + +if [ -n "$LAC" ]; then + LAC_NUM=$(printf "%d" 0x$LAC) + LAC=$LAC" ("$LAC_NUM")" +else + LAC="-" + LAC_NUM="-" +fi + +URAT1=$(echo $URAT | cut -d, -f2) +URAT2=$(echo $URAT | cut -d, -f3) +if [ -n "$URAT1" ]; then + MODTYPE="5" + case $URAT1 in + "0" ) + NETMODE="3" + ;; + "2" ) + NETMODE="5" + ;; + "3" ) + NETMODE="7" + ;; + * ) + case $URAT2 in + "0" ) + NETMODE="2" + ;; + "2" ) + NETMODE="4" + ;; + "3" ) + NETMODE="1" + ;; + esac + ;; + esac +fi + +echo 'CSQ="'"$CSQ"'"' > /tmp/signal$CURRMODEM.file +echo 'CSQ_PER="'"$CSQ_PER"'"' >> /tmp/signal$CURRMODEM.file +echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' >> /tmp/signal$CURRMODEM.file +echo 'ECIO="'"$ECIO"'"' >> /tmp/signal$CURRMODEM.file +echo 'RSCP="'"$RSCP"'"' >> /tmp/signal$CURRMODEM.file +echo 'ECIO1="'"$ECIO1"'"' >> /tmp/signal$CURRMODEM.file +echo 'RSCP1="'"$RSCP1"'"' >> /tmp/signal$CURRMODEM.file +echo 'MODE="'"$MODE"'"' >> /tmp/signal$CURRMODEM.file +echo 'MODTYPE="'"$MODTYPE"'"' >> /tmp/signal$CURRMODEM.file +echo 'NETMODE="'"$NETMODE"'"' >> /tmp/signal$CURRMODEM.file +echo 'CHANNEL="'"$CHANNEL"'"' >> /tmp/signal$CURRMODEM.file +echo 'LBAND="'"$LBAND"'"' >> /tmp/signal$CURRMODEM.file +echo 'LAC="'"$LAC"'"' >> /tmp/signal$CURRMODEM.file +echo 'LAC_NUM="'""'"' >> /tmp/signal$CURRMODEM.file +echo 'CID="'"$CID"'"' >> /tmp/signal$CURRMODEM.file +echo 'CID_NUM="'""'"' >> /tmp/signal$CURRMODEM.file +echo 'RNC="'"$RNC"'"' >> /tmp/signal$CURRMODEM.file +echo 'RNC_NUM="'"$RNC_NUM"'"' >> /tmp/signal$CURRMODEM.file +echo 'TEMP="'"$TEMP"'"' >> /tmp/signal$CURRMODEM.file +echo 'PCI="'"$PCI"'"' >> /tmp/signal$CURRMODEM.file +echo 'SINR="'"$SINR"'"' >> /tmp/signal$CURRMODEM.file + +if [ "$CSQ" = "-" ]; then + log "$OX" +fi + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/common/ztedata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/ztedata.sh new file mode 100644 index 0000000..2800901 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/common/ztedata.sh @@ -0,0 +1,193 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "ZTE Data" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +fix_data() { + O=$($ROOTER/common/processat.sh "$OY") +} + +process_csq() { + CSQ=$(echo "$O" | awk -F[,\ ] '/^\+CSQ:/ {print $2}') + [ "x$CSQ" = "x" ] && CSQ=-1 + if [ $CSQ -ge 0 -a $CSQ -le 31 ]; then + CSQ_PER=$(($CSQ * 100/31)) + CSQ_RSSI=$((2 * CSQ - 113)) + CSQX=$CSQ_RSSI + [ $CSQ -eq 0 ] && CSQ_RSSI="<= "$CSQ_RSSI + [ $CSQ -eq 31 ] && CSQ_RSSI=">= "$CSQ_RSSI + CSQ_PER=$CSQ_PER"%" + CSQ_RSSI=$CSQ_RSSI" dBm" + else + CSQ="-" + CSQ_PER="-" + CSQ_RSSI="-" + fi +} + +process_zte() { + ZRSSI=$(echo "$O" | awk -F[,\ ] '/^\+ZRSSI:/ {print $2}') + if [ "x$ZRSSI" != "x" ]; then + TMP_RSSI=$CSQ_RSSI + CSQ_RSSI="-"$ZRSSI" dBm" + ECI=$(echo "$O" | awk -F[,\ ] '/^\+ZRSSI:/ {print $3}') + if [ "x$ECI" != "x" ]; then + ECIO=`expr $ECI / 2` + ECIO="-"$ECIO + RSCP=$(echo "$O" | awk -F[,\ ] '/^\+ZRSSI:/ {print $4}') + if [ "x$RSCP" != "x" ]; then + RSCP=`expr $RSCP / 2` + RSCP="-"$RSCP + else + CSQ_RSSI=$TMP_RSSI + RSCP=$ZRSSI + ECIO=$ECI + fi + else + RSCP=$ZRSSI + CSQ_RSSI=$TMP_RSSI + ECIO=`expr $RSCP - $CSQX` + fi + fi + + MODE="-" + TECH=$(echo "$O" | awk -F[,\ ] '/^\+ZPAS:/ {print $2}' | sed 's/"//g') + if [ "x$TECH" != "x" -a "x$TECH" != "xNo" ]; then + MODE="$TECH" + fi + + ZSNT=$(echo "$O" | awk -F[,\ ] '/^\+ZSNT:/ {print $2}') + if [ "x$ZSNT" != "x" ]; then + MODTYPE="1" + if [ $ZSNT = "0" ]; then + ZSNTX=$(echo "$O" | awk -F[,\ ] '/^\+ZSNT:/ {print $4}') + case $ZSNTX in + "0" ) + NETMODE="1" + ;; + "1" ) + NETMODE="2" + ;; + "2" ) + NETMODE="4" + ;; + "6" ) + NETMODE="6" + ;; + esac + else + case $ZSNT in + "1" ) + NETMODE="3" + ;; + "2" ) + NETMODE="5" + ;; + "6" ) + NETMODE="7" + ;; + esac + fi + fi + + ZCELLINFO=$(echo $O | grep -o "+ZCELLINFO: .\+ OK") + if [ -n "$ZCELLINFO" ]; then + LBAND=$(echo $ZCELLINFO | cut -d, -f3 | grep -o "LTE B[0-9]\{1,2\}") + CHANNEL=$(echo $ZCELLINFO | cut -d, -f4 | grep -o "[0-9]\+") + if [ -n "$LBAND" ]; then + LBAND="B"$(echo $LBAND | grep -o "[0-9]\+") + else + LBAND="-" + CHANNEL="-" + fi + fi + + ZSINR=$(echo $OY | grep -o "+ZSINR: [-0-9]\{1,3\},[0-9],") + if [ -n "$ZSINR" ]; then + ZSINR=${ZSINR:8} + SINR=$(echo $ZSINR | cut -d, -f1)"."$(echo $ZSINR | cut -d, -f2)" dB" + fi + + CMODE=$(uci get modem.modem$CURRMODEM.cmode) + if [ $CMODE = 0 ]; then + NETMODE="10" + fi +} + +CSQ="-" +CSQ_PER="-" +CSQ_RSSI="-" +ECIO="-" +RSCP="-" +ECIO1=" " +RSCP1=" " +MODE="-" +MODETYPE="-" +NETMODE="-" +LBAND="-" +CHANNEL="-" +TEMP="-" +PCI="-" +SINR="-" + +OY=$($ROOTER/gcom/gcom-locked "$COMMPORT" "zteinfo.gcom" "$CURRMODEM") + +fix_data +process_csq +process_zte + +{ + echo 'CSQ="'"$CSQ"'"' > /tmp/signal$CURRMODEM.file + echo 'CSQ_PER="'"$CSQ_PER"'"' + echo 'CSQ_RSSI="'"$CSQ_RSSI"'"' + echo 'ECIO="'"$ECIO"'"' + echo 'RSCP="'"$RSCP"'"' + echo 'ECIO1="'"$ECIO1"'"' + echo 'RSCP1="'"$RSCP1"'"' + echo 'MODE="'"$MODE"'"' + echo 'MODTYPE="'"$MODTYPE"'"' + echo 'NETMODE="'"$NETMODE"'"' + echo 'LBAND="'"$LBAND"'"' + echo 'CHANNEL="'"$CHANNEL"'"' + echo 'TEMP="'"$TEMP"'"' + echo 'PCI="'"$PCI"'"' + echo 'SINR="'"$SINR"'"' +} > /tmp/signal$CURRMODEM.file + +CONNECT=$(uci get modem.modem$CURRMODEM.connected) +if [ $CONNECT -eq 0 ]; then + exit 0 +fi + +if [ $CSQ = "-" ]; then + log "$OY" +fi + +ENB="0" +if [ -e /etc/config/failover ]; then + ENB=$(uci get failover.enabled.enabled) +fi +if [ $ENB = "1" ]; then + exit 0 +fi + +WWANX=$(uci get modem.modem$CURRMODEM.interface) +OPER=$(cat /sys/class/net/$WWANX/operstate 2>/dev/null) +rm -f "/tmp/connstat"$CURRMODEM + +if [ ! $OPER ]; then + exit 0 +fi +if echo $OPER | grep -q "unknown"; then + exit 0 +fi + +if echo $OPER | grep -q "down"; then + echo "1" > "/tmp/connstat"$CURRMODEM +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/bandmask b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/bandmask new file mode 100644 index 0000000..8051d05 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/bandmask @@ -0,0 +1,483 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + modlog "Band Mask $CURRMODEM" "$@" +} + +CURRMODEM=$1 +MODTYPE=$2 + +CPORT=$(uci get modem.modem$CURRMODEM.commport) + +sierrabandmask() { + enb=$(uci -q get custom.bandlock.enabled) + ATCMDD='AT!ENTERCND="A710";!BAND?' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if [ $enb == "1" ]; then + log " " + log "Sierra Response : $OX" + log " " + fi + OX=$(echo $OX | tr " " '\x0a') + line=$OX + Unk=$(echo $line | grep "Unknown") + if [ "$Unk" ]; then + BND=$(echo $line | cut -d, -f6 | tr " " ",") + if [ $enb == "1" ]; then + log "Unknw : $BND" + fi + L1=$(echo $BND | cut -d, -f11) + GW=$(echo $BND | cut -d, -f10) + L2=$(echo $BND | cut -d, -f13) + else + all=$(echo $line | grep "L Band Mask 2") + if [ "$all" ]; then + BND=$(echo $line | cut -d, -f4 | tr " " ",") + if [ $enb == "1" ]; then + log "EM7511 : $BND" + fi + OK=8 + EOK=$(echo $BND | cut -d, -f$OK) + while [ $EOK != "OK" ]; do + OK=$(( OK + 1 )) + EOK=$(echo $BND | cut -d, -f$OK) + done + if [ $enb == "1" ]; then + log "$OK" + fi + ex1=$(( OK - 5 )) + ex2=$(( OK - 6 )) + ex3=$(( OK - 3 )) + L1=$(echo $BND | cut -d, -f$ex1) + GW=$(echo $BND | cut -d, -f$ex2) + L2=$(echo $BND | cut -d, -f$ex3) + else + BND=$(echo $line | cut -d, -f5 | tr " " ",") + if [ $enb == "1" ]; then + log "$BND" + fi + L1=$(echo $BND | cut -d, -f3) + GW=$(echo $BND | cut -d, -f2) + L2=$(echo $BND | cut -d, -f5) + fi + fi + if [ ! $L2 ]; then + L2="0000000000000000" + fi + if [ $L2 = "OK" ]; then + L2="0000000000000000" + fi + if [ $enb == "1" ]; then + log " " + log "LTE Band Mask : $L2$L1" + log " " + fi + uci set modem.modem$CURRMODEM.GW="$GW" + uci set modem.modem$CURRMODEM.L1="0x$L2$L1" + uci set modem.modem$CURRMODEM.L1X="$L1" + uci set modem.modem$CURRMODEM.L2="$L2" + uci commit modem + ATCMDD='AT!ENTERCND="AWRONG"' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +} + +quebandmask() { + enb=$(uci -q get custom.bandlock.enabled) + idP=$(uci get modem.modem$CURRMODEM.idP) + CPORT=$(uci get modem.modem$CURRMODEM.commport) + ATCMDD="AT+CGMM" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + model=$(echo "$OX" | tr '\n' ' ' | cut -d' ' -f2) + uci set modem.modem$CURRMODEM.model=$model + ATCMDD='AT+QCFG="band"' + EM160=0 + if [ $enb == "1" ]; then + log " " + log "Modem PID : $idP" + log "Modem Model : $model" + log " " + fi + if [ $idP = "0620" -o $idP = "0800" -o $idP = "030b" -o $idP = "0900" -o $idP = "0801" ]; then + EM20=$(echo $model | grep "EM20") + if [ -z "$EM20" ]; then + EM160=1 + ATCMDD='AT+QNWPREFCFG="lte_band"' + fi + fi + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if [ $enb == "1" ]; then + log " " + log "Quectel Response : $OX" + log " " + fi + L5="" + L6="" + EMT=0 + + if [ $EM160 = $EMT ]; then + qm=$(echo $OX" " | grep "+QCFG:" | tr -d '"' | tr " " ",") + if [ $enb == "1" ]; then + log "$qm" + log " " + fi + L1=$(echo $qm | cut -d, -f5) + GW=$(echo $qm | cut -d, -f4) + L2="0" + else + qm=$(echo $OX" " | grep "+QNWPREFCFG:" | tr -d '"' | tr " " ":" | tr "," ":") + if [ $enb == "1" ]; then + log "$qm" + log " " + fi + bd=5 + msk="" + L1=$(echo $qm | cut -d: -f"$bd") + while [ $L1 != "OK" ] + do + msk=$msk$L1" " + bd=$((bd+1)) + L1=$(echo $qm | cut -d: -f"$bd") + done + L1=$(encodemask $msk) + if [ -z "$L1" ]; then + L1="0" + fi + L2="0" + GW="0" + EMT=0800 + + if [ $idP = $EMT -o $idP = 0900 -o $idP = "0801" ]; then + ATCMDD='AT+QNWPREFCFG="nsa_nr5g_band"' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + qm=$(echo $OX" " | grep "+QNWPREFCFG:" | tr -d '"' | tr " " ":" | tr "," ":") + if [ $enb == "1" ]; then + log "EM160/RM500 $qm" + fi + bd=5 + msk="" + L5=$(echo $qm | cut -d: -f"$bd") + + while [ $L5 != "OK" ] + do + msk=$msk$L5" " + bd=$((bd+1)) + L5=$(echo $qm | cut -d: -f"$bd") + done + if [ -z "$msk" -o $msk = "0" ]; then + L5="0" + else + L5=$(encodemask $msk) + fi + + ATCMDD='AT+QNWPREFCFG="nr5g_band"' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + qm=$(echo $OX" " | grep "+QNWPREFCFG:" | tr -d '"' | tr " " ":" | tr "," ":") + if [ $enb == "1" ]; then + log "EM160/RM500 $qm" + fi + bd=5 + msk="" + L6=$(echo $qm | cut -d: -f"$bd") + + while [ $L6 != "OK" ] + do + msk=$msk$L6" " + bd=$((bd+1)) + L6=$(echo $qm | cut -d: -f"$bd") + done + if [ -z "$msk" -o $msk = "0" ]; then + L6="0" + else + L6=$(encodemask $msk) + fi + $ROOTER/luci/celltype.sh $CURRMODEM + netmode=$(uci -q get modem.modem$CURRMODEM.netmode) + NET="0" + if [ -e /etc/qfake ]; then + if [ $netmode = "7" ]; then + NET=8 + fi + else + if [ $netmode = "8" ]; then + NET=8 + fi + if [ $netmode = "9" ]; then + NET=9 + fi + fi + uci set modem.modem$CURRMODEM.NET="$NET" + if [ $NET = "8" -a $L1 = "0" ]; then + if [ $enb == "1" ]; then + log "NSA no LTE" + fi + fi + fi + fi + if [ $enb == "1" ]; then + log " " + log "LTE Band Mask : $L1" + log "5G NSA Band Mask : $L5" + log "5G NA Band Mask : $L6" + log " " + fi + uci set modem.modem$CURRMODEM.GW="$GW" + uci set modem.modem$CURRMODEM.L1="$L1" + uci set modem.modem$CURRMODEM.L2="$L2" + uci set modem.modem$CURRMODEM.L5="$L5" + uci set modem.modem$CURRMODEM.L6="$L6" + uci commit modem +} + +fibomask() { + enb=$(uci -q get custom.bandlock.enabled) + CPORT=$(uci get modem.modem$CURRMODEM.commport) + msk="" + NRsupport=false + ATCMDD='AT+GTACT=?' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$(echo $OX | grep -o "+GTACT:[^)]\+") + if [ -n "$OX" ]; then + RATlist=$(echo $OX | grep -o "[0-9]\{2\}") + for RATval in $(echo "$RATlist"); do + if [ $RATval == "14" -o $RATval == "16" -o $RATval == "17" -o $RATval == "20" ]; then + NRsupport=true + fi + done + ATCMDD='AT+GTACT?' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$(echo $OX" " | grep "+GTACT:" | tr -d '"' | tr " " ",") + else + ATCMDD='AT+XACT?' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$(echo $OX" " | grep "+XACT:" | tr -d '"' | tr " " ",") + if [ -z "$OX" ]; then + ATCMDD="" + OX="No AT command found to read bands" + fi + fi + LTEbands=$(echo "$OX" | grep -o "1[0-9]\{2\}") + NRbands=$(echo "$OX" | grep -o "50[0-9]\{1,3\}") + for bandval in $(echo "$LTEbands"); do + msk=$msk$((bandval-100))" " + done + if [ -n "$msk" ]; then + L1=$(encodemask $msk) + else + L1="0" + fi + msk="" + for bandval in $(echo "$NRbands"); do + msk=$msk${bandval:2}" " + done + if [ $enb == "1" ]; then + log " " + log "Get Current Bands : $ATCMDD" + log "Current Bands : $OX" + log " " + fi + if [ -z "$msk" ]; then + if $NRsupport; then + L5="0x0" + else + L5="" + fi + else + L5="0x"$(encodemask $msk) + fi + if [ -n "$L1$L5" ]; then + if [ $enb == "1" ]; then + log " " + log "LTE Band Mask : $L1" + log "5G Band Mask : $L5" + log " " + fi + uci set modem.modem$CURRMODEM.L1="0x$L1" + uci set modem.modem$CURRMODEM.L5="$L5" + uci commit modem + fi +} + +t77mask() { + enb=$(uci -q get custom.bandlock.enabled) + ATCMDD='AT^SLBAND?' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if [ $enb == "1" ]; then + log " " + log "T77 Response : $OX" + log " " + fi + lte=$(echo $OX" " | tr "," ":" | tr " " ",") + if [ $enb == "1" ]; then + log " " + log "T77 Response : $lte" + log " " + fi + qm=$(echo $lte | cut -d, -f5) + log "$qm" + bd=3 + msk="" + L1=$(echo $qm | cut -d: -f"$bd") + while [ $L1 != "OK" ] + do + msk=$msk$L1" " + bd=$((bd+1)) + L1=$(echo $qm | cut -d: -f"$bd") + done + L1=$(encodemask $msk) + if [ -z "$L1" ]; then + L1="0" + fi + if [ $enb == "1" ]; then + log " " + log "LTE Band Mask : $L1" + log " " + fi + uci set modem.modem$CURRMODEM.L1="0x$L1" + uci commit modem +} + +reversebit() { + LX=$1 + length=${#LX} + jx="${LX:2:length-2}" + length=${#jx} + str="" + i=$((length-1)) + while [ $i -ge 0 ] + do + dgt="0x"${jx:$i:1} + DecNum=`printf "%d" $dgt` + Binary= + Number=$DecNum + while [ $DecNum -ne 0 ] + do + Bit=$(expr $DecNum % 2) + Binary=$Bit$Binary + DecNum=$(expr $DecNum / 2) + done + if [ -z $Binary ]; then + Binary="0000" + fi + len=${#Binary} + while [ $len -lt 4 ] + do + Binary="0"$Binary + len=${#Binary} + done + revstr="" + length=${#Binary} + ii=$((length-1)) + while [ $ii -ge 0 ] + do + revstr=$revstr${Binary:$ii:1} + ii=$((ii-1)) + done + str=$str$revstr + i=$((i-1)) + done + revstr=$str"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +} + +reverse() { + REV="" + BNDD=$1 + strlen=${#BNDD} + i=$((strlen-1)) + while [ $i -ge 0 ] + do + REV=$REV${BNDD:$i:1} + i=$((i-1)) + done +} + +telitbandmask() { + enb=$(uci -q get custom.bandlock.enabled) + ATCMDD='AT#BND?' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if [ $enb == "1" ]; then + log " " + log "Telit Response : $OX" + log " " + fi + OX=$(echo $OX | tr " " '\x0a') + line=$OX + bnd=$(echo $line | grep "BND: ") + if [ ! -z "$bnd" ]; then + line=$(echo $bnd | tr " " ',') + if [ $enb == "1" ]; then + log "$line" + fi + BND=$(echo $line | cut -d, -f5) + ext=$(echo $line | cut -d, -f6) + reverse $BND + revs=$REV"0000000000000000" + revs=${revs:0:16} + reverse $revs + EXT="" + if [ "$ext" != "OK" -a "$ext" != "0" ]; then + EXT=$ext + fi + revs=$EXT$REV + if [ $enb == "1" ]; then + log " " + log "LTE Band Mask : $revs" + log " " + fi + ATCMDD='AT#BND=?' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$(echo $OX | tr " " '\x0a') + OX=$(echo ${OX//),(/!}) + BND=$(echo $OX"!!" | cut -d! -f3) + extt=$(echo $OX"!!" | cut -d! -f4) + if [ ! -z "$extt" ]; then + extt=$(echo $extt | tr "(" ',') + extt=$(echo $extt | tr ")" ',') + extt=$(echo $extt",," | cut -d, -f1) + fi + BND=$(echo $BND | tr "(" ',') + BND=$(echo $BND | tr ")" ',') + BND=$(echo $BND",," | cut -d, -f1) + reverse $BND + revx=$REV"0000000000000000" + revx=${revx:0:16} + reverse $revx + revx=$extt$REV + revx=${revx:0:18} + reversebit "0x"$revx + revstr=${revstr:0:72} + if [ $enb == "1" ]; then + log " " + log "LTE Bit Mask : $revstr" + log " " + fi + + uci set modem.modem$CURRMODEM.GW="0" + uci set modem.modem$CURRMODEM.L1="0x$revs" + uci set modem.modem$CURRMODEM.L1X="$revstr" + uci set modem.modem$CURRMODEM.LEXT="$extt" + uci set modem.modem$CURRMODEM.L2="0" + uci commit modem + fi +} + +case $MODTYPE in + "0" ) + sierrabandmask + ;; + "1" ) + quebandmask + ;; + "2" ) + fibomask + ;; + "3" ) + t77mask + ;; + "4" ) + telitbandmask + ;; +esac + +$ROOTER/luci/mask.sh diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/conmon.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/conmon.sh new file mode 100644 index 0000000..fece3af --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/conmon.sh @@ -0,0 +1,188 @@ +#!/bin/sh +. /lib/functions.sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "Connection Monitor $CURRMODEM" "$@" +} + +CURRMODEM=$1 + +power_toggle() { + if [ -f "/tmp/gpiopin" ]; then + source /tmp/gpiopin + echo "$GPIOPIN" > /sys/class/gpio/export + if [ $? -eq 0 ]; then + $ROOTER/pwrtoggle.sh 3 + else + $ROOTER/pwrtoggle.sh $CURRMODEM + fi + else + if [ $ACTIVE = 4 ]; then +# GPIO power-toggle not supported so re-bind USB driver, but only if power toggle is configured in connection monitoring + if [ $(uci -q get modem.pinginfo$CURRMODEM.alive) = 4 ]; then + $ROOTER/pwrtoggle.sh $CURRMODEM + fi +# if [ -L /sys/bus/usb/drivers/usb/usb1 ]; then +# if [ $(uci get modem.pinginfo1.alive) = 4 ]; then +# $ROOTER/pwrtoggle.sh 1 +# fi +# fi +# if [ -L /sys/bus/usb/drivers/usb/usb2 ]; then +# if [ $(uci get modem.pinginfo2.alive) = 4 ]; then +# $ROOTER/pwrtoggle.sh 2 +# fi +# fi + fi + fi +} + +do_down() { + echo 'MONSTAT="'"DOWN$1"'"' > /tmp/monstat$CURRMODEM + case $ACTIVE in + "1" ) + log "Modem $CURRMODEM Connection is Down$1" + ;; + "2" ) + log "Modem $CURRMODEM Connection is Down$1" + reboot -f + ;; + "3" ) + log "Modem $CURRMODEM Connection is Down$1" + PROT=$(uci get modem.modem$CURRMODEM.proto) + if [ $PROT -eq "30" ]; then + CPORT=$(uci get modem.modem$CURRMODEM.commport) + ATCMDD="AT+CFUN=4;+CFUN=1,1" + $ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD" + echo "1" > /tmp/modgone + log "Setting Modem Removal flag" + sleep 60 + else + if [ -f $ROOTER_LINK/reconnect$CURRMODEM ]; then + $ROOTER_LINK/reconnect$CURRMODEM $CURRMODEM & + fi + fi + ;; + "4" ) + log "Modem $CURRMODEM Connection is Down$1" + power_toggle + ;; + esac +} + +CURSOR="-" + +log "Start Connection Monitor for Modem $CURRMODEM" + +sleep 30 + +while [ 1 = 1 ]; do + CP=$(uci -q get ping.ping.enable) + if [ $CP = "1" ]; then + echo 'MONSTAT="'"Custom Ping Test"'"' > /tmp/monstat$CURRMODEM + sleep 60 + else + ACTIVE=$(uci get modem.pinginfo$CURRMODEM.alive) + if [ $ACTIVE = "0" ]; then + echo 'MONSTAT="'"Disabled"'"' > /tmp/monstat$CURRMODEM + sleep 60 + else + track_ips= + IFNAME=$(uci get modem.modem$CURRMODEM.interface) + TIMEOUT=$(uci get modem.pinginfo$CURRMODEM.pingwait) + INTERVAL=$(uci get modem.pinginfo$CURRMODEM.pingtime) + RELIAB=$(uci get modem.pinginfo$CURRMODEM.reliability) + DOWN=$(uci get modem.pinginfo$CURRMODEM.down) + UP=$(uci get modem.pinginfo$CURRMODEM.up) + COUNT=$(uci get modem.pinginfo$CURRMODEM.count) + PACKETSIZE=$(uci get modem.pinginfo$CURRMODEM.packetsize) + INTERF=$(uci get modem.modeminfo$CURRMODEM.inter) + + list_track_ips() { + track_ips="$1 $track_ips" + } + + config_load modem + config_list_foreach "pinginfo$CURRMODEM" "trackip" list_track_ips + + if [ -f "/tmp/connstat$CURRMODEM" ]; then + do_down " from Modem" + rm -f /tmp/connstat$CURRMODEM + sleep 20 + else + ENB="0" + if [ -e /etc/config/failover ]; then + ENB=$(uci get failover.enabled.enabled) + fi + if [ $ENB = "1" ]; then + if [ -e /tmp/mdown$CURRMODEM ]; then + do_down " (using Failover)" + else + echo 'MONSTAT="'"Up ($CURSOR) (using Failover)"'"' > /tmp/monstat$CURRMODEM + fi + sleep 20 + else + # check to see if modem iface has an IP address, if not try a reconnect/power toggle + OX=$(ip address show $IFNAME 2>&1) + ip4=$(echo "$OX" | grep 'inet ' | cut -d' ' -f6) + ip6=$(echo "$OX" | grep 'inet6' | grep global | cut -d' ' -f6) + if [ -z "$ip4" -a -z "$ip6" ]; then + do_down " (no IP address)" + fi + + UPDWN="0" + host_up_count=0 + score_up=$UP + score_dwn=$DOWN + lost=0 + while true; do + if [ ! -z "$track_ips" ]; then + for track_ip in $track_ips; do + ping -I $IFNAME -c $COUNT -W $TIMEOUT -s $PACKETSIZE -q $track_ip &> /dev/null + if [ $? -eq 0 ]; then + let host_up_count++ + else + let lost++ + fi + done + if [ $host_up_count -lt $RELIAB ]; then + let score_dwn-- + score_up=$UP + if [ $score_dwn -eq 0 ]; then + UPDWN="1" + break + fi + else + let score_up-- + score_dwn=$DOWN + if [ $score_up -eq 0 ]; then + UPDWN="0" + break + fi + fi + else + UPDWN="0" + exit + fi + host_up_count=0 + sleep $INTERVAL + done + if [ $UPDWN = "1" ]; then + do_down " (using Ping Test)" + else + echo 'MONSTAT="'"UP ($CURSOR) (using Ping Test)"'"' > /tmp/monstat$CURRMODEM + fi + sleep $INTERVAL + + fi + fi + if [ $CURSOR = "-" ]; then + CURSOR="+" + else + CURSOR="-" + fi + fi + fi +done diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_connect.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_connect.sh new file mode 100644 index 0000000..7561519 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_connect.sh @@ -0,0 +1,1360 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "Create Connection $CURRMODEM" "$@" +} + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + +handle_timeout(){ + local wget_pid="$1" + local count=0 + TIMEOUT=70 + res=1 + if [ -d /proc/${wget_pid} ]; then + res=0 + fi + while [ "$res" = 0 -a $count -lt "$((TIMEOUT))" ]; do + sleep 1 + count=$((count+1)) + res=1 + if [ -d /proc/${wget_pid} ]; then + res=0 + fi + done + + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill "$wget_pid" 2> /dev/null + res=1 + if [ -d /proc/${wget_pid} ]; then + res=0 + fi + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill -9 $wget_pid 2> /dev/null + fi + fi +} + +set_dns() { + local pDNS1=$(uci -q get modem.modeminfo$CURRMODEM.dns1) + local pDNS2=$(uci -q get modem.modeminfo$CURRMODEM.dns2) + local pDNS3=$(uci -q get modem.modeminfo$CURRMODEM.dns3) + local pDNS4=$(uci -q get modem.modeminfo$CURRMODEM.dns4) + + local aDNS="$pDNS1 $pDNS2 $pDNS3 $pDNS4" + local bDNS="" + + echo "$aDNS" | grep -o "[[:graph:]]" &>/dev/null + if [ $? = 0 ]; then + log "Using DNS settings from the Connection Profile" + pdns=1 + for DNSV in $(echo "$aDNS"); do + if [ "$DNSV" != "0.0.0.0" ] && [ -z "$(echo "$bDNS" | grep -o "$DNSV")" ]; then + [ -n "$(echo "$DNSV" | grep -o ":")" ] && continue + bDNS="$bDNS $DNSV" + fi + done + + bDNS=$(echo $bDNS) + if [ $DHCP = 1 ]; then + uci set network.wan$INTER.peerdns=0 + uci set network.wan$INTER.dns="$bDNS" + fi + echo "$bDNS" > /tmp/v4dns$INTER + + bDNS="" + for DNSV in $(echo "$aDNS"); do + if [ "$DNSV" != "0:0:0:0:0:0:0:0" ] && [ -z "$(echo "$bDNS" | grep -o "$DNSV")" ]; then + [ -z "$(echo "$DNSV" | grep -o ":")" ] && continue + bDNS="$bDNS $DNSV" + fi + done + echo "$bDNS" > /tmp/v6dns$INTER + else + log "Using Provider assigned DNS" + pdns=0 + rm -f /tmp/v[46]dns$INTER + fi +} + +set_dns2() { + local pDNS1=$(uci -q get modem.modeminfo$CURRMODEM.dns1) + local pDNS2=$(uci -q get modem.modeminfo$CURRMODEM.dns2) + local pDNS3=$(uci -q get modem.modeminfo$CURRMODEM.dns3) + local pDNS4=$(uci -q get modem.modeminfo$CURRMODEM.dns4) + + local _DNS1 _DNS2 _DNS3 _DNS4 aDNS bDNS + + echo "$pDNS1 $pDNS2 $pDNS3 $pDNS4" | grep -o "[[:graph:]]" &>/dev/null + if [ $? = 0 ]; then + log "Using DNS settings from the Connection Profile" + pdns=1 + _DNS1=$pDNS1 + _DNS2=$pDNS2 + _DNS3=$pDNS3 + _DNS4=$pDNS4 + else + log "Using Provider assigned DNS" + pdns=0 + _DNS1=$DNS1 + _DNS2=$DNS2 + _DNS3=$DNS3 + _DNS4=$DNS4 + fi + + aDNS="$_DNS1 $_DNS2 $_DNS3 $_DNS4" + + bDNS="" + for DNSV in $(echo "$aDNS"); do + if [ "$DNSV" != "0.0.0.0" ] && [ "$DNSV" != "0:0:0:0:0:0:0:0" ] && [ -z "$(echo "$bDNS" | grep -o "$DNSV")" ]; then + [ -n "$(echo "$DNSV" | grep -o ":")" ] && [ -z "$ip6" ] && continue + bDNS="$bDNS $DNSV" + fi + done + + bDNS=$(echo $bDNS) + uci set network.wan$INTER.dns="$bDNS" +} + +check_apn() { + IPVAR="IP" + local COMMPORT="/dev/ttyUSB"$CPORT + if [ -e /etc/nocops ]; then + echo "0" > /tmp/block + fi + ATCMDD="AT+CGDCONT=?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + + [ "$PDPT" = "0" ] && PDPT="" + for PDP in "$PDPT" IPV4V6; do + if [[ "$(echo $OX | grep -o "$PDP")" ]]; then + IPVAR="$PDP" + break + fi + done + + uci set modem.modem$CURRMODEM.pdptype=$IPVAR + uci commit modem + + log "PDP Type selected in the Connection Profile: \"$PDPT\", active: \"$IPVAR\"" + + if [ "$idV" = "12d1" ]; then + CFUNOFF="0" + else + CFUNOFF="4" + fi + + ATCMDD="AT+CGDCONT?;+CFUN?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + CGDCONT2=$(echo $OX | grep "+CGDCONT: 2,") + if [ -z "$CGDCONT2" ]; then + ATCMDD="AT+CGDCONT=2,\"$IPVAR\",\"ims\"" + OXy=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + if `echo $OX | grep "+CGDCONT: $CID,\"$IPVAR\",\"$NAPN\"," 1>/dev/null 2>&1` + then + if [ -z "$(echo $OX | grep -o "+CFUN: 1")" ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+CFUN=1") + fi + else + ATCMDD="AT+CGDCONT=$CID,\"$IPVAR\",\"$NAPN\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+CFUN=$CFUNOFF") + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+CFUN=1") + sleep 5 + fi + if [ -e /etc/nocops ]; then + rm -f /tmp/block + fi +} + +save_variables() { + echo 'MODSTART="'"$MODSTART"'"' > /tmp/variable.file + echo 'WWAN="'"$WWAN"'"' >> /tmp/variable.file + echo 'USBN="'"$USBN"'"' >> /tmp/variable.file + echo 'ETHN="'"$ETHN"'"' >> /tmp/variable.file + echo 'WDMN="'"$WDMN"'"' >> /tmp/variable.file + echo 'BASEPORT="'"$BASEPORT"'"' >> /tmp/variable.file +} + +chcklog() { + OOX=$1 + CLOG=$(uci -q get modem.modeminfo$CURRMODEM.log) + if [ $CLOG = "1" ]; then + log "$OOX" + fi +} + +get_connect() { + NAPN=$(uci -q get modem.modeminfo$CURRMODEM.apn) + NUSER=$(uci -q get modem.modeminfo$CURRMODEM.user) + NPASS=$(uci -q get modem.modeminfo$CURRMODEM.passw) + NAUTH=$(uci -q get modem.modeminfo$CURRMODEM.auth) + spin=$(uci -q get custom.simpin.pin) # SIM Pin + if [ -z "$spin" ]; then + spin=$(uci -q get modem.modeminfo$CURRMODEM.pincode) # Profile Pin + if [ -z "$spin" ]; then + spin=$(uci -q get profile.simpin.pin) # Default profile Pin + fi + fi + PINC=$spin + uci set modem.modeminfo$CURRMODEM.pincode=$PINC + uci commit modem + PDPT=$(uci -q get modem.modeminfo$CURRMODEM.pdptype) +# +# QMI and MBIM can't handle nil +# + case $PROT in + "2"|"3"|"30"|"88" ) + if [ -z "$NUSER" ]; then + NUSER="NIL" + fi + if [ -z "$NPASS" ]; then + NPASS="NIL" + fi + ;; + esac + + uci set modem.modem$CURRMODEM.apn=$NAPN + uci set modem.modem$CURRMODEM.user=$NUSER + uci set modem.modem$CURRMODEM.passw=$NPASS + uci set modem.modem$CURRMODEM.auth=$NAUTH + uci set modem.modem$CURRMODEM.pin=$PINC + uci commit modem +} + +chksierra() { + SIERRAID=0 + if [ $idV = 1199 ]; then + case $idP in + "68aa"|"68a2"|"68a3"|"68a9"|"68b0"|"68b1" ) + SIERRAID=1 + ;; + "68c0"|"9040"|"9041"|"9051"|"9054"|"9056"|"90d3" ) + SIERRAID=1 + ;; + "9070"|"907b"|"9071"|"9079"|"901c"|"9091"|"901f"|"90b1" ) + SIERRAID=1 + ;; + esac + elif [ $idV = 114f -a $idP = 68a2 ]; then + SIERRAID=1 + elif [ $idV = 413c -a $idP = 81a8 ]; then + SIERRAID=1 + elif [ $idV = 413c -a $idP = 81b6 ]; then + SIERRAID=1 + fi +} + +chktelitmbim() { + TELITMBIM=0 + if [ $idV = 1bc7 -a $idP = 0032 ]; then + TELITMBIM=1 + fi +} + +chkT77() { + T77=0 + if [ $idV = 413c -a $idP = 81d7 ]; then + T77=1 + elif [ $idV = 413c -a $idP = 81d8 ]; then + T77=1 + elif [ $idV = 0489 -a $idP = e0b4 ]; then + T77=1 + elif [ $idV = 0489 -a $idP = e0b5 ]; then + T77=1 + elif [ $idV = 1bc7 -a $idP = 1910 ]; then + T77=1 + fi + if [ $T77 = 1 ]; then + [ -n "$TTYDEVS" ] || T77=0 + fi +} + +chkraw() { + RAW=0 + if [ $idV = 03f0 -a $idP = 0857 ]; then + RAW=1 + elif [ $idV = 1bc7 -a $idP = 1900 ]; then + RAW=1 + elif [ $idV = 1bc7 -a $idP = 1910 ]; then + RAW=1 + elif [ $idV = 19d2 -a $idP = 1432 ]; then + RAW=1 + elif [ $idV = 1e0e -a $idP = 9001 ]; then + RAW=1 + elif [ $idV = 2c7c ]; then + RAW=1 + elif [ $idV = 05c6 -a $idP = 9025 ]; then + [ $MAN = "Telit" ] || RAW=1 + elif [ $idV = 05c6 -a $idP = 90db ]; then + RAW=1 + elif [ $idV = 05c6 -a $idP = f601 ]; then + RAW=1 + elif [ $idV = 2cb7 -a $idP = 0104 ]; then + RAW=1 + elif [ $idV = 413c -a $idP = 81d7 ]; then + RAW=1 + fi +} + +chkreg() { + local OX REGV REGST REGCMD + local COMMPORT="/dev/ttyUSB"$CPORT + ATCMDD="AT+CEREG?;+CREG?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + for REGCMD in +CEREG +CREG; do + REGV=$(echo "$OX" | grep -o "$REGCMD: [0-3],[0-9]") + if [ -n "$REGV" ]; then + REGST=$(echo "$REGV" | cut -d, -f2) + case $REGST in + "0" ) + continue + ;; + "1"|"5"|"6"|"7" ) + REGOK=1 + break + ;; + * ) + REGOK=0 + ;; + esac + fi + done +} + +addv6() { + . /lib/functions.sh + . /lib/netifd/netifd-proto.sh + local interface=wan$INTER + local zone="$(fw3 -q network "$interface" 2>/dev/null)" + + log "Adding IPv6 dynamic interface" + json_init + json_add_string name "${interface}_6" + json_add_string ${ifname1} "@$interface" + json_add_string proto "dhcpv6" + json_add_string extendprefix 1 + [ -n "$zone" ] && json_add_string zone "$zone" + [ "$pdns" = 1 ] && json_add_boolean peerdns 0 + [ "$nat46" = 1 ] || json_add_string iface_464xlat 0 + proto_add_dynamic_defaults + json_close_object + ubus call network add_dynamic "$(json_dump)" +} + +get_tty() { +# $1 is bInterfaceNumber value + local IFNUM OX + IFNUM=$1 + for TTYD in $(echo "$TTYDEVS"); do + if [ ! "$ACM" = 1 ]; then + OX=$(cat /sys/class/tty/$TTYD/../../../bInterfaceNumber | grep "$IFNUM") + else + OX=$(cat /sys/class/tty/$TTYD/../../bInterfaceNumber | grep "$IFNUM") + fi + if [ $? = 0 ]; then + CPORT=$(echo $TTYD | grep -o "[[:digit:]]\+") + break + else + CPORT="" + fi + done +} + +get_tty_fix() { +# $1 is fixed ttyUSB or ttyACM port number + local POS + POS=`expr 1 + $1` + CPORT=$(echo "$TTYDEVS" | cut -d' ' -f"$POS" | grep -o "[[:digit:]]\+") +} + +get_tty_ncm() { + local IFPROT OX + PROTS="12 62 02 2" # PC UI interface bInterfaceProtocol value + for IFPROT in $PROTS; do + for TTYD in $(echo "$TTYDEVS"); do + OX=$(cat /sys/class/tty/$TTYD/../../../bInterfaceProtocol | grep -w "$IFPROT") + if [ $? = 0 ]; then + CPORT=$(echo $TTYD | grep -o "[[:digit:]]\+") + break 2 + else + CPORT="" + fi + done + done +} + +mbimcport() { + lua $ROOTER/common/modemchk.lua "$idV" "$idP" "$CPORT" "$CPORT" + source /tmp/parmpass + uci set modem.modem$CURRMODEM.commport=$CPORT + uci set modem.modem$CURRMODEM.proto="30" + log "MBIM Comm Port : /dev/ttyUSB$CPORT" +} + +CURRMODEM=$1 +RECON=$2 +SIERRAID=0 + +MAN=$(uci -q get modem.modem$CURRMODEM.manuf) +MOD=$(uci -q get modem.modem$CURRMODEM.model) +PROT=$(uci -q get modem.modem$CURRMODEM.proto) +idV=$(uci -q get modem.modem$CURRMODEM.idV) +idP=$(uci -q get modem.modem$CURRMODEM.idP) + +if [ ! -z "$RECON" ]; then + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "ReConnecting" + uci set modem.modem$CURRMODEM.active=1 + uci set modem.modem$CURRMODEM.connected=0 + uci commit modem + INTER=$(uci -q get modem.modeminfo$CURRMODEM.inter) + jkillall getsignal$CURRMODEM + rm -f $ROOTER_LINK/getsignal$CURRMODEM + jkillall con_monitor$CURRMODEM + rm -f $ROOTER_LINK/con_monitor$CURRMODEM + jkillall mbim_monitor$CURRMODEM + rm -f $ROOTER_LINK/mbim_monitor$CURRMODEM + ifdown wan$INTER + CPORT=$(uci -q get modem.modem$CURRMODEM.commport) + WWANX=$(uci -q get modem.modem$CURRMODEM.wwan) + WDMNX=$(uci -q get modem.modem$CURRMODEM.wdm) + if [ "$RECON" = "1" ]; then + $ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "reset.gcom" "$CURRMODEM" + fi +else + + DELAY=$(uci -q get modem.modem$CURRMODEM.delay) + if [ -z "$DELAY" ]; then + DELAY=5 + fi + +rm -f /tmp/usbwait + +MATCH="$(uci get modem.modem$CURRMODEM.maxcontrol | cut -d/ -f3- | xargs dirname)" + +case $PROT in + # Sierra Direct-IP data interface + + "1" ) + OX="$(for a in /sys/class/net/*; do readlink $a; done | grep "$MATCH")" + ifname=$(basename $OX) + WWANX=$(echo $ifname | grep -o "[[:digit:]]") + log "Modem $CURRMODEM Sierra Direct-IP Device : $ifname" + + uci set modem.modem$CURRMODEM.wwan=$WWANX + uci set modem.modem$CURRMODEM.interface=$ifname + uci commit modem + ;; + + # QMI, NCM and MBIM use cdc-wdm + + "2"|"3"|"30"|"4"|"6"|"7" ) + OX="$(for a in /sys/class/usbmisc/*; do readlink $a; done | grep "$MATCH")" + devname=$(basename $OX) + log "Modem $CURRMODEM WDM Device : $devname" + WDMNX=$(echo $devname | grep -o "[[:digit:]]") + ifname="$(ls /sys/class/usbmisc/$devname/device/net/)" + WWANX=$(echo $ifname | grep -o "[[:digit:]]") + + uci set modem.modem$CURRMODEM.wdm=$WDMNX + uci set modem.modem$CURRMODEM.wwan=$WWANX + uci set modem.modem$CURRMODEM.interface=$ifname + uci commit modem + ;; +esac + +OX=$(for a in /sys/class/tty/*; do readlink $a; done | grep "$MATCH" | tr '\n' ' ' | xargs -r -n1 basename) +TTYDEVS=$(echo "$OX" | grep -o ttyUSB[0-9]) +if [ $? -ne 0 ]; then + TTYDEVS=$(echo "$OX" | grep -o ttyACM[0-9]) + [ $? -eq 0 ] && ACM=1 +fi +TTYDEVS=$(echo "$TTYDEVS" | tr '\n' ' ') +TTYDEVS=$(echo $TTYDEVS) +if [ -n "$TTYDEVS" ]; then + log Modem $CURRMODEM is a parent of $TTYDEVS +else + log "No Comm Ports" +fi + +get_tty_fix 0 +if [ -n "$CPORT" ]; then + uci set modem.modem$CURRMODEM.baseport=$CPORT +else + uci set modem.modem$CURRMODEM.baseport="" +fi +uci commit modem.modem$CURRMODEM + + case $PROT in +# +# Sierra Direct-IP modem comm port +# + "1" ) + log "Start Direct-IP Connection" + get_tty 03 + lua $ROOTER/common/modemchk.lua "$idV" "$idP" "$CPORT" "$CPORT" + source /tmp/parmpass + log "Sierra Comm Port : /dev/ttyUSB$CPORT" + ;; +# +# QMI modem comm port +# + "2"|"88" ) + log "Start QMI (RMNET) Connection" + sleep $DELAY + + chksierra + if [ $SIERRAID -eq 1 ]; then + get_tty 03 + elif [ $idV = 1bc7 ]; then + get_tty 03 + else + if [ $idV = 2c7c ]; then + QUEIF2="0121 0125 0306 0296 0512 0620 0800 030b 0801 0900" + if [[ $(echo "$QUEIF2" | grep -o -i "$idP") ]]; then + TPORT=2 + fi + elif [ $idV = 05c6 -a $idP = 9025 ]; then + [ $MAN = "Telit" ] || TPORT=2 + elif [ $idV = 1e0e -a $idP = 9001 ]; then + TPORT=2 + else + TPORT=1 + fi + get_tty_fix $TPORT + fi + + lua $ROOTER/common/modemchk.lua "$idV" "$idP" "$CPORT" "$CPORT" + source /tmp/parmpass + + log "Modem $CURRMODEM QMI (RMNET) Comm Port : /dev/ttyUSB$CPORT" + chkraw + ;; + "3"|"30" ) + log "Start MBIM Connection" + sleep $DELAY + + chksierra + if [ $SIERRAID -eq 1 ]; then + SIERRAIF2='1199:90b1' + if [[ $(echo $SIERRAIF2 | grep -o -i "$idV:$idP") ]]; then + IFNUM=02 + else + IFNUM=03 + fi + get_tty $IFNUM + if [ -z "$CPORT" ]; then + if [ $idP = "90d3" ]; then + get_tty_fix 0 + lua $ROOTER/common/modemchk.lua "$idV" "$idP" "$CPORT" "$CPORT" + source /tmp/parmpass + uci set modem.modem$CURRMODEM.commport=$CPORT + if [ -n "$CPORT" ]; then + uci set modem.modem$CURRMODEM.proto="30" + fi + log "Modem $CURRMODEM MBIM Comm Port : /dev/ttyUSB$CPORT" + else + uci set modem.modem$CURRMODEM.commport="" + uci set modem.modem$CURRMODEM.proto="3" + log "No MBIM Comm Port" + fi + else + mbimcport + fi + else + chktelitmbim + if [ $TELITMBIM -eq 1 ]; then + get_tty 00 + lua $ROOTER/common/modemchk.lua "$idV" "$idP" "$CPORT" "$CPORT" + source /tmp/parmpass + ACMPORT=$CPORT + CPORT=9$ACMPORT + ln -fs /dev/ttyACM$ACMPORT /dev/ttyUSB$CPORT + uci set modem.modem$CURRMODEM.commport=$CPORT + if [ -n "$CPORT" ]; then + uci set modem.modem$CURRMODEM.proto="30" + fi + log "Modem $CURRMODEM MBIM Comm Port : /dev/ttyUSB$CPORT" + else + chkT77 + if [ $T77 -eq 1 ]; then + get_tty 02 + mbimcport + else + case $idV in + "2c7c"|"05c6" ) + get_tty_fix 2 + mbimcport + ;; + "03f0" ) + get_tty 02 + mbimcport + ;; + "1bc7" ) + if [ "$idP" = "1041" ]; then + get_tty 07 + else + get_tty 02 + fi + mbimcport + ;; + "2cb7" ) + get_tty_fix 0 + lua $ROOTER/common/modemchk.lua "$idV" "$idP" "$CPORT" "$CPORT" + source /tmp/parmpass + ACMPORT=$CPORT + CPORT="8$ACMPORT" + ln -fs /dev/ttyACM$ACMPORT /dev/ttyUSB$CPORT + + uci set modem.modem$CURRMODEM.commport=$CPORT + uci set modem.modem$CURRMODEM.proto="30" + log "Modem $CURRMODEM MBIM Comm Port : /dev/ttyUSB$CPORT" + ;; + * ) + uci set modem.modem$CURRMODEM.commport="" + log "No MBIM Comm Port" + ;; + esac + fi + fi + fi + uci commit modem + ;; +# +# Huawei NCM +# + "4"|"6"|"7"|"24"|"26"|"27" ) + if [ "$idV" = "2c7c" -a "$idP" = "0900" ]; then + ATCMDD='AT+QCFG="usbnet",2' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB2" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ATCMDD='AT+CFUN=1,1' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB2" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + reboot -f + fi + log "Start NCM Connection" + sleep $DELAY + + get_tty_ncm + lua $ROOTER/common/modemchk.lua "$idV" "$idP" "$CPORT" "$CPORT" + source /tmp/parmpass + + log "NCM Comm Port : /dev/ttyUSB$CPORT" + ;; + "28" ) + log "Start Fibocom NCM Connection" + get_tty_fix 2 + lua $ROOTER/common/modemchk.lua "$idV" "$idP" "$CPORT" "$CPORT" + source /tmp/parmpass + ACMPORT=$CPORT + CPORT="8$ACMPORT" + ln -fs /dev/ttyACM$ACMPORT /dev/ttyUSB$CPORT + log "Modem $CURRMODEM Fibocom NCM Comm Port : /dev/ttyUSB$CPORT" + ;; + esac + + uci set modem.modem$CURRMODEM.commport=$CPORT + uci commit modem + +fi +if [ $PROT = "3" ]; then +# May have got changed to 30 above + PROT=$(uci -q get modem.modem$CURRMODEM.proto) +fi +if [ -z "$idV" ]; then + idV=$(uci -q get modem.modem$CURRMODEM.idV) +fi +QUECTEL=false +if [ "$idV" = "2c7c" ]; then + QUECTEL=true +elif [ "$idV" = "05c6" ]; then + QUELST="9090,9003,9215" + if [[ $(echo "$QUELST" | grep -o "$idP") ]]; then + QUECTEL=true + fi +fi + +if [ -e $ROOTER/connect/preconnect.sh ]; then + if [ "$RECON" != "2"|"88" ]; then + $ROOTER/connect/preconnect.sh $CURRMODEM + fi +fi + +if $QUECTEL; then + if [ "$RECON" != "2"|"88" ]; then + ATCMDD="AT+CNMI?" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if `echo $OX | grep -o "+CNMI: [0-3],2," >/dev/null 2>&1`; then + ATCMDD="AT+CNMI=0,0,0,0,0" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + ATCMDD="AT+QINDCFG=\"smsincoming\"" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if `echo $OX | grep -o ",1" >/dev/null 2>&1`; then + ATCMDD="AT+QINDCFG=\"smsincoming\",0,1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + ATCMDD="AT+QINDCFG=\"all\"" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if `echo $OX | grep -o ",1" >/dev/null 2>&1`; then + ATCMDD="AT+QINDCFG=\"all\",0,1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + log "Quectel Unsolicited Responses Disabled" + fi + $ROOTER/connect/bandmask $CURRMODEM 1 + clck=$(uci -q get custom.bandlock.cenable$CURRMODEM) + if [ $clck = "1" ]; then + ear=$(uci -q get custom.bandlock.earfcn$CURRMODEM) + pc=$(uci -q get custom.bandlock.pci$CURRMODEM) + ear1=$(uci -q get custom.bandlock.earfcn1$CURRMODEM) + pc1=$(uci -q get custom.bandlock.pci1$CURRMODEM) + ear2=$(uci -q get custom.bandlock.earfcn2$CURRMODEM) + pc2=$(uci -q get custom.bandlock.pci2$CURRMODEM) + ear3=$(uci -q get custom.bandlock.earfcn3$CURRMODEM) + pc3=$(uci -q get custom.bandlock.pci3$CURRMODEM) + cnt=1 + earcnt=$ear","$pc + if [ $ear1 != "0" -a $pc1 != "0" ]; then + earcnt=$earcnt","$ear1","$pc1 + let cnt=cnt+1 + fi + if [ $ear2 != "0" -a $pc2 != "0" ]; then + earcnt=$earcnt","$ear2","$pc2 + let cnt=cnt+1 + fi + if [ $ear3 != "0" -a $pc3 != "0" ]; then + earcnt=$earcnt","$ear3","$pc3 + let cnt=cnt+1 + fi + earcnt=$cnt","$earcnt + ATCMDD="at+qnwlock=\"common/4g\"" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + log "$OX" + if `echo $OX | grep "ERROR" 1>/dev/null 2>&1` + then + ATCMDD="at+qnwlock=\"common/lte\",2,$ear,$pc" + else + ATCMDD=$ATCMDD","$earcnt + fi + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + log "Cell Lock $OX" + sleep 10 + fi +fi +$ROOTER/luci/celltype.sh $CURRMODEM +if [ $SIERRAID -eq 1 ]; then + $ROOTER/connect/bandmask $CURRMODEM 0 + $ROOTER/luci/celltype.sh $CURRMODEM +fi +if [ $idV = "2dee" ]; then + ATC="AT^MODE=0" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATC") +fi +if [ $idV = "2cb7" -o $idV = "8087" ]; then + $ROOTER/connect/bandmask $CURRMODEM 2 +fi + +chkT77 +if [ $T77 -eq 1 ]; then + $ROOTER/connect/bandmask $CURRMODEM 3 +fi + +if [ $idV = "1bc7" ]; then + if [ $idP = "1040" -o $idP = "1041" ]; then + $ROOTER/connect/bandmask $CURRMODEM 4 + fi +fi + +CHKPORT=$(uci -q get modem.modem$CURRMODEM.commport) +if [ -n "$CHKPORT" ]; then + $ROOTER/common/gettype.sh $CURRMODEM + $ROOTER/connect/get_profile.sh $CURRMODEM + if [ -e $ROOTER/simlock.sh ]; then + $ROOTER/simlock.sh $CURRMODEM + fi + + if [ -e /tmp/simpin$CURRMODEM ]; then + log " SIM Error" + exit 0 + fi + if [ -e /usr/lib/gps/gps.sh ]; then + /usr/lib/gps/gps.sh $CURRMODEM & + fi + INTER=$(uci -q get modem.modeminfo$CURRMODEM.inter) + [ $INTER = 3 ] && log "Modem $CURRMODEM disabled in Connection Profile" && exit 1 + $ROOTER/sms/check_sms.sh $CURRMODEM & + get_connect + if [ -z "$INTER" ]; then + INTER=$CURRMODEM + else + if [ $INTER = 0 ]; then + INTER=$CURRMODEM + fi + fi + log "Profile for Modem $CURRMODEM sets interface to WAN$INTER" + OTHER=1 + if [ $CURRMODEM = 1 ]; then + OTHER=2 + fi + EMPTY=$(uci -q get modem.modem$OTHER.empty) + if [ $EMPTY = 0 ]; then + OINTER=$(uci -q get modem.modem$OTHER.inter) + if [ ! -z "$OINTER" ]; then + if [ $INTER = $OINTER ]; then + INTER=1 + if [ $OINTER = 1 ]; then + INTER=2 + fi + log "Switched Modem $CURRMODEM to WAN$INTER as Modem $OTHER is using WAN$OINTER" + fi + fi + fi + uci set modem.modem$CURRMODEM.inter=$INTER + uci commit modem + log "Modem $CURRMODEM is using WAN$INTER" + + CID=$(uci -q get modem.modeminfo$CURRMODEM.context) + [ -z "$CID" ] && CID=1 + + DHCP=1 + if [ $PROT = 28 ]; then + DHCP=0 + elif [ $PROT = 2 -a $idV = 05c6 -a $idP = 9025 ]; then + [ $MAN = "Telit" ] || DHCP=0 + fi + NODHCP=$(uci -q get modem.modeminfo$CURRMODEM.nodhcp) + if [ $idV = "2c7c" -a $idP = "0801" ]; then + NODHCP="1" + fi + if [ "$NODHCP" = "1" ]; then + DHCP=0 + log "Using QMI without DHCP" + fi + + if [ $DHCP = 1 ]; then + uci delete network.wan$INTER + uci set network.wan$INTER=interface + uci set network.wan$INTER.proto=dhcp + uci set network.wan$INTER.${ifname1}=$ifname + uci set network.wan$INTER._orig_bridge=false + uci set network.wan$INTER.metric=$INTER"0" + set_dns + uci commit network + else + set_dns + fi + + ttl=$(uci -q get modem.modeminfo$CURRMODEM.ttl) + if [ -z "$ttl" ]; then + ttl="0" + fi + $ROOTER/connect/handlettl.sh $CURRMODEM "$ttl" & + + if [ -e $ROOTER/changedevice.sh ]; then + $ROOTER/changedevice.sh $ifname + fi + + autoapn=$(uci -q get profile.disable.autoapn) + imsi=$(uci -q get modem.modem$CURRMODEM.imsi) + mcc6=${imsi:0:6} + mcc5=${imsi:0:5} + apd=0 + if [ -e /usr/lib/autoapn/apn.data ]; then + apd=1 + fi + if [ "$autoapn" = "1" -a $apd -eq 1 ]; then + isplist=$(grep -F "$mcc6" '/usr/lib/autoapn/apn.data') + if [ -z "$isplist" ]; then + isplist=$(grep -F "$mcc5" '/usr/lib/autoapn/apn.data') + if [ -z "$isplist" ]; then + isplist="000000,$NAPN,Default,$NPASS,$CID,$NUSER,$NAUTH" + fi + fi + else + isplist="000000,$NAPN,Default,$NPASS,$CID,$NUSER,$NAUTH" + fi + + uci set modem.modeminfo$CURRMODEM.isplist="$isplist" + uci commit modem + + if [ $idV = 12d1 ]; then + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "curc.gcom" "$CURRMODEM") + log "Huawei Unsolicited Responses Disabled" + ATCMDD="AT^USSDMODE=0" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + FORCE=$(uci -q get modem.modeminfo$CURRMODEM.ppp) + if [ -n "$FORCE" ]; then + if [ $FORCE = 1 ]; then + log "Forcing PPP mode" + case $idV in + "12d1" ) + retval=10 + ;; + * ) + retval=11 + ;; + esac + uci set modem.modem$CURRMODEM.proto=$retval + rm -f $ROOTER_LINK/create_proto$CURRMODEM + log "Forced Protcol Value : $retval" + log "Connecting a PPP Modem" + ln -fs $ROOTER/ppp/create_ppp.sh $ROOTER_LINK/create_proto$CURRMODEM + $ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM & + exit 0 + fi + fi +fi + +if $QUECTEL; then + ATCMDD="AT+QINDCFG=\"all\",1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +fi + +modis=$(uci -q get basic.basic.modem) +if [ ! -z $modis ]; then + if [ $modis = "0" ]; then + log "Modem Disabled" + exit 0 + fi +fi + +for isp in $isplist +do + NAPN=$(echo $isp | cut -d, -f2) + NPASS=$(echo $isp | cut -d, -f4) + CID=$(echo $isp | cut -d, -f5) + NUSER=$(echo $isp | cut -d, -f6) + NAUTH=$(echo $isp | cut -d, -f7) + if [ "$NPASS" = "nil" ]; then + NPASS="NIL" + fi + if [ "$NUSER" = "nil" ]; then + NUSER="NIL" + fi + if [ "$NAUTH" = "nil" ]; then + NAUTH="0" + fi + export SETAPN=$NAPN + export SETUSER=$NUSER + export SETPASS=$NPASS + export SETAUTH=$NAUTH + export PINCODE=$PINC + + uci set modem.modem$CURRMODEM.apn=$NAPN + uci set modem.modem$CURRMODEM.user=$NUSER + uci set modem.modem$CURRMODEM.passw=$NPASS + uci set modem.modem$CURRMODEM.auth=$NAUTH + uci set modem.modem$CURRMODEM.pin=$PINC + uci commit modem + + concount=1 + while [ "$concount" -lt 3 ]; do + case $PROT in + "1" ) + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "auto.gcom" "$CURRMODEM") + chcklog "$OX" + M7=$(echo "$OX" | sed -e "s/SCPROF:/SCPROF: /;s! ! !g") + AU=$(echo "$M7" | awk -F[,\ ] '/^\!SCPROF:/ {print $4}') + if [ $AU = "1" ]; then + AUTO="1" + log "Autoconnect is Enabled" + else + AUTO="0" + log "Autoconnect is not Enabled" + fi + ;; + esac + uci set modem.modem$CURRMODEM.auto=$AUTO + uci commit modem + + case $PROT in + # + # Check provider Lock + # + "1"|"2"|"4"|"6"|"7"|"24"|"26"|"27"|"30"|"28"|"88" ) + $ROOTER/common/lockchk.sh $CURRMODEM + ;; + * ) + log "No Provider Lock Done" + ;; + esac + + case $PROT in + # + # Sierra and NCM uses separate Pincode setting + # + "1"|"4"|"6"|"7"|"24"|"26"|"27"|"28" ) + if [ -n "$PINC" ]; then + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "setpin.gcom" "$CURRMODEM") + chcklog "$OX" + ERROR="ERROR" + if `echo $OX | grep "$ERROR" 1>/dev/null 2>&1` + then + log "Modem $CURRMODEM Failed to Unlock SIM Pin" + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Pin Locked" + exit 0 + fi + fi + ;; + * ) + log "Pincode in script" + ;; + esac + $ROOTER/log/logger "Attempting to Connect Modem #$CURRMODEM" + log "Attempting to Connect Modem $CURRMODEM" + + if [ -e $ROOTER/modem-led.sh ]; then + $ROOTER/modem-led.sh $CURRMODEM 2 + fi + + BRK=0 + case $PROT in + # + # Sierra connect script + # + "1" ) + if [ $AUTO = "0" ]; then + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "connect-directip.gcom" "$CURRMODEM") + chcklog "$OX" + ERROR="ERROR" + if `echo $OX | grep "$ERROR" 1>/dev/null 2>&1` + then + BRK=1 + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Retrying" + fi + M7=$(echo "$OX" | sed -e "s/SCACT:/SCACT: /;s! ! !g") + SCACT="!SCACT: 1,1" + if `echo ${M7} | grep "$SCACT" 1>/dev/null 2>&1` + then + BRK=0 + ifup wan$INTER + sleep 20 + else + BRK=1 + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Retrying" + fi + else + ifup wan$INTER + sleep 20 + fi + ;; + # + # QMI connect script + # + "2" ) + check_apn + $ROOTER/qmi/connectqmi.sh $CURRMODEM cdc-wdm$WDMNX $NAUTH $NAPN $NUSER $NPASS $RAW $DHCP $PINC + if [ $? = 0 ]; then + ifup wan$INTER + [ -f /tmp/ipv6supp$INTER ] && addv6 + else + exit 0 + fi + ;; + # + # NCM connect script + # + "4"|"6"|"7"|"24"|"26"|"27" ) + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "ati") + E5372=$(echo $OX | grep "E5372") + R215=$(echo $OX | grep "R215") + E5787=$(echo $OX | grep "E5787") + check_apn + if [ -n "$E5372" -o -n "$R215" -o -n "$E5787" ]; then + ifup wan$INTER + BRK=0 + else + OX=$($ROOTER/gcom/gcom-locked "/dev/cdc-wdm$WDMNX" "connect-ncm.gcom" "$CURRMODEM") + chcklog "$OX" + ERROR="ERROR" + if `echo $OX | grep "$ERROR" 1>/dev/null 2>&1` + then + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "connect-ncm.gcom" "$CURRMODEM") + chcklog "$OX" + fi + ERROR="ERROR" + if `echo $OX | grep "$ERROR" 1>/dev/null 2>&1` + then + BRK=1 + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Retrying" + else + ifup wan$INTER + sleep 25 + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "cgpaddr.gcom" "$CURRMODEM") + chcklog "$OX" + OX=$($ROOTER/common/processat.sh "$OX") + STATUS=$(echo "$OX" | awk -F[,\ ] '/^\^SYSINFOEX:/ {print $2}' | sed 's/"//g') + DOMAIN=$(echo "$OX" | awk -F[,\ ] '/^\^SYSINFOEX:/ {print $3}' | sed 's/"//g') + if [ "x$STATUS" = "x" ]; then + STATUS=$(echo "$OX" | awk -F[,\ ] '/^\^SYSINFO:/ {print $2}') + DOMAIN=$(echo "$OX" | awk -F[,\ ] '/^\^SYSINFO:/ {print $3}') + fi + CGPADDR="+CGPADDR:" + if `echo $OX | grep "$CGPADDR" 1>/dev/null 2>&1` + then + if [ $STATUS = "2" ]; then + if [ $DOMAIN = "1" ]; then + BRK=0 + else + if [ $DOMAIN = "2" ]; then + BRK=0 + else + if [ $DOMAIN = "3" ]; then + BRK=0 + else + BRK=1 + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Network Error : Retrying" + fi + fi + fi + else + BRK=1 + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Network Error : Retrying" + fi + else + BRK=1 + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "No IP Address : Retrying" + fi + fi + fi + [ $BRK = 0 ] && addv6 + ;; + # + # Fibocom NCM connect + # + "28" ) + OX="$(for a in /sys/class/net/*; do readlink $a; done | grep "$MATCH" | grep ".6/net/")" + ifname=$(basename $OX) + log "Modem $CURRMODEM Fibocom NCM Data Port : $ifname" + COMMPORT="/dev/ttyUSB"$CPORT + ATCMDD="AT+CGACT=0,$CID" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + check_apn + ATCMDD="AT+CGPIAF=1,0,0,0;+XDNS=$CID,1;+XDNS=$CID,2" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ATCMDD="AT+CGACT=1,$CID" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ERROR="ERROR" + if [ -e /tmp/simerr$CURRMODEM ]; then + SIMFAIL=1 + log "SIM card error" + else + chkreg + [ "$REGOK" != 1 ] && log "Subscriber registration failed" + fi + if [ "$SIMFAIL" = 1 -o "$REGOK" != 1 ]; then + BRK=1 + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Retrying" + elif `echo "$OX" | grep -q "$ERROR"`; then + BRK=1 + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Retrying" + else + ATCMDD="AT+CGCONTRDP=$CID" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if `echo "$OX" | grep -q "$ERROR"`; then + log "Failed to get IP information for context $CID" + BRK=1 + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to get IP information : Retrying" + else + OX=$(echo "${OX//[\" ]/}") + ip=$(echo $OX | cut -d, -f4 | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}") + ip=$(echo $ip | cut -d' ' -f1) + DNS1=$(echo $OX | cut -d, -f6) + DNS2=$(echo $OX | cut -d, -f7) + OX6=$(echo $OX | grep -o "+CGCONTRDP:$CID,[0-9]\+,[^,]\+,[0-9A-F]\{1,4\}:[0-9A-F]\{1,4\}.\+") + ip6=$(echo $OX6 | grep -o "[0-9A-F]\{1,4\}:[0-9A-F]\{1,4\}:[0-9A-F]\{1,4\}:[0-9A-F]\{1,4\}:[0-9A-F]\{1,4\}:[0-9A-F]\{1,4\}:[0-9A-F]\{1,4\}:[0-9A-F]\{1,4\}") + ip6=$(echo $ip6 | cut -d' ' -f1) + DNS3=$(echo "$OX6" | cut -d, -f6) + DNS4=$(echo "$OX6" | cut -d, -f7) + + log "IP address(es): $ip $ip6" + log "DNS servers 1&2: $DNS1 $DNS2" + log "DNS servers 3&4: $DNS3 $DNS4" + + if [[ $(echo "$ip6" | grep -o "^[23]") ]]; then + # Global unicast IP acquired + v6cap=1 + elif [[ $(echo "$ip6" | grep -o "^[0-9a-fA-F]\{1,4\}:") ]]; then + # non-routable address + v6cap=2 + else + v6cap=0 + fi + + if [ -n "$ip6" -a -z "$ip" ]; then + log "Running IPv6-only mode" + nat46=1 + fi + + ATCMDD="AT+XDATACHANNEL=1,1,\"/USBCDC/2\",\"/USBHS/NCM/0\",2,$CID" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + RDNS=$(uci -q get network.wan$INTER.dns) + + log "Applying IP settings to wan$INTER" + uci delete network.wan$INTER + uci set network.wan$INTER=interface + uci set network.wan$INTER.proto=static + uci set network.wan$INTER.${ifname1}=$ifname + uci set network.wan$INTER.metric=$INTER"0" + if [ -n "$ip" ]; then + uci set network.wan$INTER.ipaddr=$ip/32 + uci set network.wan$INTER.gateway='0.0.0.0' + fi + if [ "$v6cap" -gt 0 ]; then + uci set network.wan$INTER.ip6addr=$ip6/128 + fi + + if [ -n "$RDNS" ]; then + uci set network.wan$INTER.dns="$RDNS" + else + set_dns2 + fi + + uci commit network + uci set modem.modem$CURRMODEM.interface=$ifname + uci commit modem + ip link set dev $ifname arp off + ATCMDD="AT+CGDATA=\"M-RAW_IP\",$CID" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "raw-ip.gcom" "$CURRMODEM" "$ATCMDD") + RESP=$(echo $OX | sed "s/AT+CGDATA=\"M-RAW_IP\",$CID //") + log "Final Modem $CURRMODEM result code is \"$RESP\"" + if [ "$RESP" = "OK CONNECT" ]; then + ifup wan$INTER + if [ -e /sys/class/net/$ifname/cdc_ncm/tx_timer_usecs ]; then + echo "0" > /sys/class/net/$ifname/cdc_ncm/tx_timer_usecs + fi + [ $v6cap = 2 ] && addv6 + sleep 2 + BRK=0 + else + BRK=1 + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Retrying" + fi + fi + fi + ;; + # + # MBIM connect script + # + "3"|"30" ) + if [ -n "$CPORT" ]; then + check_apn + fi + log "Using Netifd Method" + uci delete network.wan$INTER + uci set network.wan$INTER=interface + uci set network.wan$INTER.proto=mbim + uci set network.wan$INTER.device=/dev/cdc-wdm$WDMNX + uci set network.wan$INTER.metric=$INTER"0" + uci set network.wan$INTER.currmodem=$CURRMODEM + uci -q commit network + rm -f /tmp/usbwait + ifup wan$INTER + MIFACE=$(uci -q get modem.modem$CURRMODEM.interface) + if [ -e /sys/class/net/$MIFACE/cdc_ncm/tx_timer_usecs ]; then + echo "0" > /sys/class/net/$MIFACE/cdc_ncm/tx_timer_usecs + fi + exit 0 + ;; + esac + + if [ $BRK = 1 ]; then + ATCMDD="AT+COPS=0" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + $ROOTER/log/logger "Retry Connection with Modem #$CURRMODEM" + log "Retry Connection" + sleep 10 + concount=$((concount+1)) + else + $ROOTER/log/logger "Modem #$CURRMODEM Connected" + log "Modem $CURRMODEM Connected" + break + fi + done + if [ $BRK = 0 ]; then + break + fi +done + +if [ $BRK = 1 ]; then + exit 0 +fi + +if [ -e $ROOTER/modem-led.sh ]; then + $ROOTER/modem-led.sh $CURRMODEM 3 +fi + +case $PROT in +# +# Sierra, NCM and QMI use modemsignal.sh and reconnect.sh +# + "1"|"2"|"4"|"6"|"7"|"24"|"26"|"27"|"28"|"88" ) + ln -fs $ROOTER/signal/modemsignal.sh $ROOTER_LINK/getsignal$CURRMODEM + ln -fs $ROOTER/connect/reconnect.sh $ROOTER_LINK/reconnect$CURRMODEM + # send custom AT startup command + if [ $(uci -q get modem.modeminfo$CURRMODEM.at) -eq "1" ]; then + ATCMDD=$(uci -q get modem.modeminfo$CURRMODEM.atc) + if [ ! -z "$ATCMDD" ]; then + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$($ROOTER/common/processat.sh "$OX") + ERROR="ERROR" + if `echo $OX | grep "$ERROR" 1>/dev/null 2>&1` + then + log "Error sending custom AT command: $ATCMDD with result: $OX" + else + log "Sent custom AT command: $ATCMDD with result: $OX" + fi + fi + fi + ;; +esac + + $ROOTER_LINK/getsignal$CURRMODEM $CURRMODEM $PROT & + ln -fs $ROOTER/connect/conmon.sh $ROOTER_LINK/con_monitor$CURRMODEM + $ROOTER_LINK/con_monitor$CURRMODEM $CURRMODEM & + uci set modem.modem$CURRMODEM.connected=1 + uci commit modem + + if [ -e $ROOTER/connect/postconnect.sh ]; then + $ROOTER/connect/postconnect.sh $CURRMODEM + fi + + if [ -e /etc/bandlock ]; then + M1='AT+COPS=?' + export TIMEOUT="120" + #OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$M1") + export TIMEOUT="5" + fi + + if [ -e $ROOTER/timezone.sh ]; then + TZ=$(uci -q get modem.modeminfo$CURRMODEM.tzone) + if [ "$TZ" = "1" ]; then + log "Set TimeZone" + $ROOTER/timezone.sh & + fi + fi + + CLB=$(uci -q get modem.modeminfo$CURRMODEM.lb) + if [ -e /etc/config/mwan3 ]; then + ENB=$(uci -q get mwan3.wan$INTER.enabled) + if [ ! -z "$ENB" ]; then + if [ $CLB = "1" ]; then + uci set mwan3.wan$INTER.enabled=1 + else + uci set mwan3.wan$INTER.enabled=0 + fi + uci commit mwan3 + /usr/sbin/mwan3 restart + fi + fi + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_hostless.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_hostless.sh new file mode 100644 index 0000000..192dcba --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_hostless.sh @@ -0,0 +1,666 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "Create Hostless Connection $CURRMODEM" "$@" +} + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + +handle_timeout(){ + local wget_pid="$1" + local count=0 + ps | grep -v grep | grep $wget_pid + res="$?" + while [ "$res" = 0 -a $count -lt "$((TIMEOUT))" ]; do + sleep 1 + count=$((count+1)) + ps | grep -v grep | grep $wget_pid + res="$?" + done + + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill "$wget_pid" 2> /dev/null + ps | grep -v grep | grep $wget_pid + res="$?" + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill -9 $wget_pid 2> /dev/null + fi + fi +} + +check_apn() { + IPVAR="IP" + local COMMPORT="/dev/ttyUSB"$CPORT + if [ -e /etc/nocops ]; then + echo "0" > /tmp/block + fi + ATCMDD="AT+CGDCONT=?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + + [ "$PDPT" = "0" ] && PDPT="" + for PDP in "$PDPT" IPV4V6; do + if [[ "$(echo $OX | grep -o "$PDP")" ]]; then + IPVAR="$PDP" + break + fi + done + + uci set modem.modem$CURRMODEM.pdptype=$IPVAR + uci commit modem + + log "PDP Type selected in the Connection Profile: \"$PDPT\", active: \"$IPVAR\"" + + if [ "$idV" = "12d1" ]; then + CFUNOFF="0" + else + CFUNOFF="4" + fi + ATCMDD="AT+CGDCONT?;+CFUN?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + CGDCONT2=$(echo $OX | grep "+CGDCONT: 2,") + if [ -z "$CGDCONT2" ]; then + ATCMDD="AT+CGDCONT=2,\"$IPVAR\",\"ims\"" + OXy=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + CGDCONT=$(echo $OX | grep -o "$CID,[^,]\+,[^,]\+,[^,]\+,0,0,1") + IPCG=$(echo $CGDCONT | cut -d, -f4) + if [ "$CGDCONT" == "$CID,\"$IPVAR\",\"$NAPN\",$IPCG,0,0,1" ]; then + if [ -z "$(echo $OX | grep -o "+CFUN: 1")" ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+CFUN=1") + fi + else + ATCMDD="AT+CGDCONT=$CID,\"$IPVAR\",\"$NAPN\",,0,0,1" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+CFUN=$CFUNOFF") + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+CFUN=1") + sleep 5 + fi +} + +set_dns() { + local pDNS1=$(uci -q get modem.modeminfo$CURRMODEM.dns1) + local pDNS2=$(uci -q get modem.modeminfo$CURRMODEM.dns2) + local pDNS3=$(uci -q get modem.modeminfo$CURRMODEM.dns3) + local pDNS4=$(uci -q get modem.modeminfo$CURRMODEM.dns4) + + local aDNS="$pDNS1 $pDNS2 $pDNS3 $pDNS4" + local bDNS="" + + echo "$aDNS" | grep -o "[[:graph:]]" &>/dev/null + if [ $? = 0 ]; then + log "Using DNS settings from the Connection Profile" + pdns=1 + for DNSV in $(echo "$aDNS"); do + if [ "$DNSV" != "0.0.0.0" ] && [ -z "$(echo "$bDNS" | grep -o "$DNSV")" ]; then + [ -n "$(echo "$DNSV" | grep -o ":")" ] && continue + bDNS="$bDNS $DNSV" + fi + done + + bDNS=$(echo $bDNS) + uci set network.wan$INTER.peerdns=0 + uci set network.wan$INTER.dns="$bDNS" + echo "$bDNS" > /tmp/v4dns$INTER + + bDNS="" + for DNSV in $(echo "$aDNS"); do + if [ "$DNSV" != "0:0:0:0:0:0:0:0" ] && [ -z "$(echo "$bDNS" | grep -o "$DNSV")" ]; then + [ -z "$(echo "$DNSV" | grep -o ":")" ] && continue + bDNS="$bDNS $DNSV" + fi + done + echo "$bDNS" > /tmp/v6dns$INTER + else + log "Using Hostless Modem as a DNS relay" + pdns=0 + rm -f /tmp/v[46]dns$INTER + fi +} + +set_network() { + uci delete network.wan$INTER + uci set network.wan$INTER=interface + uci set network.wan$INTER.proto=dhcp + uci set network.wan$INTER.${ifname1}=$1 + uci set network.wan$INTER.metric=$INTER"0" + set_dns + uci commit network + sleep 5 +} + +save_variables() { + echo 'MODSTART="'"$MODSTART"'"' > /tmp/variable.file + echo 'WWAN="'"$WWAN"'"' >> /tmp/variable.file + echo 'USBN="'"$USBN"'"' >> /tmp/variable.file + echo 'ETHN="'"$ETHN"'"' >> /tmp/variable.file + echo 'WDMN="'"$WDMN"'"' >> /tmp/variable.file + echo 'BASEPORT="'"$BASEPORT"'"' >> /tmp/variable.file +} + +chcklog() { + OOX=$1 + CLOG=$(uci -q get modem.modeminfo$CURRMODEM.log) + if [ $CLOG = "1" ]; then + log "$OOX" + fi +} + +get_connect() { + NAPN=$(uci -q get modem.modeminfo$CURRMODEM.apn) + PDPT=$(uci -q get modem.modeminfo$CURRMODEM.pdptype) + uci set modem.modem$CURRMODEM.apn="$NAPN" + uci commit modem +} + +get_tty_fix() { +# $1 is fixed ttyUSB or ttyACM port number + local POS + POS=`expr 1 + $1` + CPORT=$(echo "$TTYDEVS" | cut -d' ' -f"$POS" | grep -o "[[:digit:]]\+") +} + +get_ip() { + ATCMDD="AT+CGPIAF=1,1,1,0;+CGPADDR" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$(echo "$OX" | grep "^+CGPADDR: $CID," | cut -d'"' -f2) + ip4=$(echo $OX | cut -d, -f1 | grep "\.") + ip6=$(echo $OX | cut -d, -f2 | grep ":") + log "IP address(es) obtained: $ip4 $ip6" +} + +check_ip() { + if [[ $(echo "$ip6" | grep -o "^[23]") ]]; then + # Global unicast IP acquired + v6cap=1 + elif [[ $(echo "$ip6" | grep -o "^[0-9a-fA-F]\{1,4\}:") ]]; then + # non-routable address + v6cap=2 + else + v6cap=0 + fi + + if [ -n "$ip6" -a -z "$ip4" ]; then + log "Running IPv6-only mode" + nat46=1 + fi +} + +addv6() { + . /lib/functions.sh + . /lib/netifd/netifd-proto.sh + local interface=wan$INTER + local zone="$(fw3 -q network "$interface" 2>/dev/null)" + + log "Adding IPv6 dynamic interface" + json_init + json_add_string name "${interface}_6" + json_add_string ${ifname1} "@$interface" + json_add_string proto "dhcpv6" + json_add_string extendprefix 1 + [ -n "$zone" ] && json_add_string zone "$zone" + [ "$pdns" = 1 ] && json_add_boolean peerdns 0 + [ "$nat46" = 1 ] || json_add_string iface_464xlat 0 + proto_add_dynamic_defaults + json_close_object + ubus call network add_dynamic "$(json_dump)" +} + +CURRMODEM=$1 + +MAN=$(uci -q get modem.modem$CURRMODEM.manuf) +MOD=$(uci -q get modem.modem$CURRMODEM.model) +$ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Connecting" +$ROOTER/log/logger "Attempting to Connect Modem #$CURRMODEM ($MAN $MOD)" + +BASEP=$(uci -q get modem.modem$CURRMODEM.baseport) +idV=$(uci -q get modem.modem$CURRMODEM.idV) +idP=$(uci -q get modem.modem$CURRMODEM.idP) +log " " +log "Hostless ID $idV:$idP" +log " " + +MATCH="$(uci -q get modem.modem$CURRMODEM.maxcontrol | cut -d/ -f3- | xargs dirname)" +OX=$(for a in /sys/class/tty/*; do readlink $a; done | grep "$MATCH" | tr '\n' ' ' | xargs -r -n1 basename) +TTYDEVS=$(echo "$OX" | grep -o ttyUSB[0-9]) +if [ $? -ne 0 ]; then + TTYDEVS=$(echo "$OX" | grep -o ttyACM[0-9]) + [ $? -eq 0 ] && ACM=1 +fi +TTYDEVS=$(echo "$TTYDEVS" | tr '\n' ' ') +TTYDEVS=$(echo $TTYDEVS) +if [ -n "$TTYDEVS" ]; then + log Modem $CURRMODEM is a parent of $TTYDEVS +else + log "No ECM Comm Port" +fi + +if [ $idV = 1546 -a $idP = 1146 ]; then + SP=1 +elif [ $idV = 19d2 -a $idP = 1476 ]; then + SP=2 +elif [ $idV = 1410 -a $idP = 9022 ]; then + SP=3 +elif [ $idV = 1410 -a $idP = 9032 ]; then + SP=3 +elif [ $idV = 2cb7 -o $idV = 1508 ]; then + sleep 5 + log "Fibocom ECM" + SP=4 +elif [ $idV = 2c7c ]; then + SP=5 +elif [ $idV = 12d1 -a $idP = 15c1 ]; then + SP=6 +elif [ $idV = 2cd2 ]; then + log "MikroTik R11e ECM" + SP=7 +else + SP=0 +fi + +log " " +log "Modem Type $SP" +log " " +if [ $SP -gt 0 ]; then + if [ $SP -eq 3 ]; then + PORTN=0 + elif [ $SP -eq 4 ]; then + PORTN=2 + elif [ $SP -eq 5 ]; then + [ $idP = 6026 ] && PORTN=1 || PORTN=2 + elif [ $SP -eq 6 ]; then + PORTN=2 + elif [ $SP -eq 7 ]; then + PORTN=0 + else + PORTN=1 + fi + get_tty_fix $PORTN + lua $ROOTER/common/modemchk.lua "$idV" "$idP" "$CPORT" "$CPORT" + source /tmp/parmpass + + if [ "$ACM" = 1 ]; then + ACMPORT=$CPORT + CPORT="7$ACMPORT" + ln -fs /dev/ttyACM$ACMPORT /dev/ttyUSB$CPORT + fi + + log "Modem $CURRMODEM ECM Comm Port : /dev/ttyUSB$CPORT" + uci set modem.modem$CURRMODEM.commport=$CPORT + uci commit modem + + $ROOTER/sms/check_sms.sh $CURRMODEM & + + if [ -e $ROOTER/connect/preconnect.sh ]; then + $ROOTER/connect/preconnect.sh $CURRMODEM + fi + + if [ $SP = 5 ]; then + clck=$(uci -q get custom.bandlock.cenable$CURRMODEM) + if [ "$clck" = "1" ]; then + ear=$(uci -q get custom.bandlock.earfcn$CURRMODEM) + pc=$(uci -q get custom.bandlock.pci$CURRMODEM) + ear1=$(uci -q get custom.bandlock.earfcn1$CURRMODEM) + pc1=$(uci -q get custom.bandlock.pci1$CURRMODEM) + ear2=$(uci -q get custom.bandlock.earfcn2$CURRMODEM) + pc2=$(uci -q get custom.bandlock.pci2$CURRMODEM) + ear3=$(uci -q get custom.bandlock.earfcn3$CURRMODEM) + pc3=$(uci -q get custom.bandlock.pci3$CURRMODEM) + cnt=1 + earcnt=$ear","$pc + if [ "$ear1" != "0" -a $pc1 != "0" ]; then + earcnt=$earcnt","$ear1","$pc1 + let cnt=cnt+1 + fi + if [ "$ear2" != "0" -a $pc2 != "0" ]; then + earcnt=$earcnt","$ear2","$pc2 + let cnt=cnt+1 + fi + if [ "$ear3" != "0" -a $pc3 != "0" ]; then + earcnt=$earcnt","$ear3","$pc3 + let cnt=cnt+1 + fi + earcnt=$cnt","$earcnt + ATCMDD="at+qnwlock=\"common/4g\"" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + log "$OX" + if `echo $OX | grep "ERROR" 1>/dev/null 2>&1` + then + ATCMDD="at+qnwlock=\"common/lte\",2,$ear,$pc" + else + ATCMDD=$ATCMDD","$earcnt + fi + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + log "Cell Lock $OX" + sleep 10 + fi + fi + + $ROOTER/connect/bandmask $CURRMODEM 1 + uci commit modem + + if [ $SP = 4 ]; then + if [ -e /etc/interwave ]; then + idP=$(uci -q get modem.modem$CURRMODEM.idP) + idPP=${idP:1:1} + if [ "$idPP" = "1" ]; then + ATC="AT+GTRAT=17" + else + ATC="AT+XACT=4,2" + fi + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATC") + fi + $ROOTER/connect/bandmask $CURRMODEM 2 + uci commit modem + fi +fi +$ROOTER/common/gettype.sh $CURRMODEM +$ROOTER/connect/get_profile.sh $CURRMODEM +if [ -e $ROOTER/simlock.sh ]; then + $ROOTER/simlock.sh $CURRMODEM +fi + +if [ -e /tmp/simpin$CURRMODEM ]; then + log " SIM Error" + exit 0 +fi +if [ -e /usr/lib/gps/gps.sh ]; then + /usr/lib/gps/gps.sh $CURRMODEM & +fi + +INTER=$(uci -q get modem.modeminfo$CURRMODEM.inter) +if [ -z "$INTER" ]; then + INTER=$CURRMODEM +else + if [ "$INTER" = 0 ]; then + INTER=$CURRMODEM + fi +fi +log "Profile for Modem $CURRMODEM sets interface to WAN$INTER" +OTHER=1 +if [ $CURRMODEM = 1 ]; then + OTHER=2 +fi +EMPTY=$(uci -q get modem.modem$OTHER.empty) +if [ "$EMPTY" = 0 ]; then + OINTER=$(uci -q get modem.modem$OTHER.inter) + if [ ! -z "$OINTER" ]; then + if [ $INTER = $OINTER ]; then + INTER=1 + if [ "$OINTER" = 1 ]; then + INTER=2 + fi + log "Switched Modem $CURRMODEM to WAN$INTER as Modem $OTHER is using WAN$OINTER" + fi + fi +fi +uci set modem.modem$CURRMODEM.inter=$INTER +uci commit modem +log "Modem $CURRMODEM is using WAN$INTER" + +CID=$(uci -q get modem.modeminfo$CURRMODEM.context) +[ -z "$CID" ] && CID=1 + +log "Checking Network Interface" +ifname="$(if [ "$MATCH" ]; then for a in /sys/class/net/*; do readlink $a; done | grep "$MATCH"; fi | xargs -r basename)" + +if [ "$ifname" ]; then + log "Modem $CURRMODEM ECM Data Port : $ifname" + set_network "$ifname" + uci set modem.modem$CURRMODEM.interface=$ifname + if [ -e $ROOTER/changedevice.sh ]; then + $ROOTER/changedevice.sh $ifname + fi +else + log "Modem $CURRMODEM - No ECM Data Port found" +fi +uci commit modem + +ttl=$(uci -q get modem.modeminfo$CURRMODEM.ttl) +if [ -z "$ttl" ]; then + ttl="0" +fi +hostless=$(uci -q get modem.modeminfo$CURRMODEM.hostless) +if [ "$ttl" != "0" -a "$ttl" != "1" -a "$ttl" != "TTL-INC 1" -a "$hostless" = "1" ]; then + let "ttl=$ttl+1" +fi +$ROOTER/connect/handlettl.sh $CURRMODEM "$ttl" + +if [ $SP -eq 2 ]; then + get_connect + export SETAPN=$NAPN + BRK=1 + + while [ $BRK -eq 1 ]; do + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "connect-zecm.gcom" "$CURRMODEM") + chcklog "$OX" + ERROR="ERROR" + if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` + then + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Retrying" + else + BRK=0 + fi + done +fi + +if [ $SP -eq 4 ]; then + get_connect + export SETAPN=$NAPN + BRK=1 + + while [ $BRK -eq 1 ]; do + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "connect-fecm.gcom" "$CURRMODEM") + chcklog "$OX" + log " " + log "Fibocom Connect : $OX" + log " " + ERROR="ERROR" + if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` + then + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Retrying" + else + BRK=0 + get_ip + fi + done +fi + +if [ $SP = 5 ]; then + get_connect + if [ -n "$NAPN" ]; then + $ROOTER/common/lockchk.sh $CURRMODEM + if [ $idP = 6026 ]; then + IPN=1 + case "$PDPT" in + "IPV6" ) + IPN=2 + ;; + "IPV4V6" ) + IPN=3 + ;; + esac + ATCMDD="AT+QICSGP=$CID,$IPN,\"$NAPN\"" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ATCMDD="AT+QNETDEVCTL=2,$CID,1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + else + check_apn + fi + fi + ATCMDD="AT+CNMI?" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if `echo $OX | grep -o "+CNMI: [0-3],2," >/dev/null 2>&1`; then + ATCMDD="AT+CNMI=0,0,0,0,0" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + ATCMDD="AT+QINDCFG=\"smsincoming\"" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if `echo $OX | grep -o ",1" >/dev/null 2>&1`; then + ATCMDD="AT+QINDCFG=\"smsincoming\",0,1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + ATCMDD="AT+QINDCFG=\"all\"" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if `echo $OX | grep -o ",1" >/dev/null 2>&1`; then + ATCMDD="AT+QINDCFG=\"all\",0,1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + log "Quectel Unsolicited Responses Disabled" + $ROOTER/luci/celltype.sh $CURRMODEM + ATCMDD="AT+QINDCFG=\"all\",1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + + get_ip + if [ -n "$ip6" ]; then + check_ip + if [ "$v6cap" -gt 0 ]; then + addv6 + fi + fi +fi + +if [ $SP -eq 6 ]; then + get_connect + export SETAPN=$NAPN + BRK=1 + + while [ $BRK -eq 1 ]; do + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "connect-ncm.gcom" "$CURRMODEM") + chcklog "$OX" + ERROR="ERROR" + if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` + then + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Retrying" + else + BRK=0 + fi + done +fi + +if [ $SP -eq 7 ]; then + get_connect + export SETAPN=$NAPN + BRK=1 + + if [ -n "$NAPN" ]; then + check_apn + fi + + while [ $BRK -eq 1 ]; do + ATCMDD="AT\$ECMCALL=1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + chcklog "$OX" + ERROR="ERROR" + if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` + then + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Connect : Retrying" + else + BRK=0 + get_ip + if [ -n "$ip6" ]; then + check_ip + if [ "$v6cap" -gt 0 ]; then + addv6 + fi + fi + fi + done +fi + +rm -f /tmp/usbwait + +ifup wan$INTER +while `ifstatus wan$INTER | grep -q '"up": false\|"pending": true'`; do + sleep 1 +done +wan_ip=$(expr "`ifstatus wan$INTER | grep '"nexthop":'`" : '.*"nexthop": "\(.*\)"') +if [ $? -ne 0 ] ; then + wan_ip=192.168.0.1 +fi +uci set modem.modem$CURRMODEM.ip=$wan_ip +uci commit modem + +$ROOTER/log/logger "HostlessModem #$CURRMODEM Connected with IP $wan_ip" + +PROT=5 + +if [ $SP -gt 1 ]; then + ln -s $ROOTER/signal/modemsignal.sh $ROOTER_LINK/getsignal$CURRMODEM + $ROOTER_LINK/getsignal$CURRMODEM $CURRMODEM $PROT & +else + VENDOR=$(uci -q get modem.modem$CURRMODEM.idV) + case $VENDOR in + "19d2" ) + TIMEOUT=3 + wget -O /tmp/connect.file http://$wan_ip/goform/goform_set_cmd_process?goformId=CONNECT_NETWORK & + handle_timeout "$!" + ln -s $ROOTER/signal/ztehostless.sh $ROOTER_LINK/getsignal$CURRMODEM + $ROOTER_LINK/getsignal$CURRMODEM $CURRMODEM $PROT & + ;; + "12d1" ) + log "Huawei Hostless" + ln -s $ROOTER/signal/huaweihostless.sh $ROOTER_LINK/getsignal$CURRMODEM + $ROOTER_LINK/getsignal$CURRMODEM $CURRMODEM $PROT & + ;; + * ) + log "Other Hostless" + ln -s $ROOTER/signal/otherhostless.sh $ROOTER_LINK/getsignal$CURRMODEM + $ROOTER_LINK/getsignal$CURRMODEM $CURRMODEM $PROT & + ;; +esac +fi + +ln -s $ROOTER/connect/conmon.sh $ROOTER_LINK/con_monitor$CURRMODEM +$ROOTER_LINK/con_monitor$CURRMODEM $CURRMODEM & +uci set modem.modem$CURRMODEM.connected=1 +uci commit modem + +if [ $SP -gt 0 ]; then + if [ -e $ROOTER/connect/postconnect.sh ]; then + $ROOTER/connect/postconnect.sh $CURRMODEM + fi + if [ $(uci -q get modem.modeminfo$CURRMODEM.at) -eq "1" ]; then + ATCMDD=$(uci -q get modem.modeminfo$CURRMODEM.atc) + if [ -n "$ATCMDD" ]; then + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$($ROOTER/common/processat.sh "$OX") + ERROR="ERROR" + if `echo $OX | grep "$ERROR" 1>/dev/null 2>&1` + then + log "Error sending custom AT command: $ATCMDD with result: $OX" + else + log "Sent custom AT command: $ATCMDD with result: $OX" + fi + fi + fi + + if [ -e $ROOTER/timezone.sh ]; then + TZ=$(uci -q get modem.modeminfo$CURRMODEM.tzone) + if [ "$TZ" = "1" ]; then + log "Set TimeZone" + $ROOTER/timezone.sh & + fi + fi +fi + +CLB=$(uci -q get modem.modeminfo$CURRMODEM.lb) +if [ -e /etc/config/mwan3 ]; then + ENB=$(uci -q get mwan3.wan$INTER.enabled) + if [ ! -z "$ENB" ]; then + if [ "$CLB" = "1" ]; then + uci set mwan3.wan$INTER.enabled=1 + else + uci set mwan3.wan$INTER.enabled=0 + fi + uci commit mwan3 + /usr/sbin/mwan3 restart + fi +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_iphone.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_iphone.sh new file mode 100644 index 0000000..fe87a5c --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/create_iphone.sh @@ -0,0 +1,222 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "Create iPhone Connection $CURRMODEM" "$@" +} + + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + +handle_timeout(){ + local wget_pid="$1" + local count=0 + ps | grep -v grep | grep $wget_pid + res="$?" + while [ "$res" = 0 -a $count -lt "$((TIMEOUT))" ]; do + sleep 1 + count=$((count+1)) + ps | grep -v grep | grep $wget_pid + res="$?" + done + + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill "$wget_pid" 2> /dev/null + ps | grep -v grep | grep $wget_pid + res="$?" + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill -9 $wget_pid 2> /dev/null + fi + fi +} + +set_dns() { + local pDNS1=$(uci -q get modem.modeminfo$CURRMODEM.dns1) + local pDNS2=$(uci -q get modem.modeminfo$CURRMODEM.dns2) + local pDNS3=$(uci -q get modem.modeminfo$CURRMODEM.dns3) + local pDNS4=$(uci -q get modem.modeminfo$CURRMODEM.dns4) + + local aDNS="$pDNS1 $pDNS2 $pDNS3 $pDNS4" + local bDNS="" + + echo "$aDNS" | grep -o "[[:graph:]]" &>/dev/null + if [ $? = 0 ]; then + log "Using DNS settings from the Connection Profile" + pdns=1 + for DNSV in $(echo "$aDNS"); do + if [ "$DNSV" != "0.0.0.0" ] && [ -z "$(echo "$bDNS" | grep -o "$DNSV")" ]; then + [ -n "$(echo "$DNSV" | grep -o ":")" ] && continue + bDNS="$bDNS $DNSV" + fi + done + + bDNS=$(echo $bDNS) + uci set network.wan$INTER.peerdns=0 + uci set network.wan$INTER.dns="$bDNS" + echo "$bDNS" > /tmp/v4dns$INTER + + bDNS="" + for DNSV in $(echo "$aDNS"); do + if [ "$DNSV" != "0:0:0:0:0:0:0:0" ] && [ -z "$(echo "$bDNS" | grep -o "$DNSV")" ]; then + [ -z "$(echo "$DNSV" | grep -o ":")" ] && continue + bDNS="$bDNS $DNSV" + fi + done + echo "$bDNS" > /tmp/v6dns$INTER + else + log "Using Hostless Modem as a DNS" + pdns=0 + rm -f /tmp/v[46]dns$INTER + fi +} + +set_network() { + uci delete network.wan$INTER + uci set network.wan$INTER=interface + uci set network.wan$INTER.proto=dhcp + uci set network.wan$INTER.${ifname1}=$1 + uci set network.wan$INTER.metric=$INTER"0" + set_dns + uci commit network + sleep 5 +} + +save_variables() { + echo 'MODSTART="'"$MODSTART"'"' > /tmp/variable.file + echo 'WWAN="'"$WWAN"'"' >> /tmp/variable.file + echo 'USBN="'"$USBN"'"' >> /tmp/variable.file + echo 'ETHN="'"$ETHN"'"' >> /tmp/variable.file + echo 'WDMN="'"$WDMN"'"' >> /tmp/variable.file + echo 'BASEPORT="'"$BASEPORT"'"' >> /tmp/variable.file +} + +chcklog() { + OOX=$1 + CLOG=$(uci -q get modem.modeminfo$CURRMODEM.log) + if [ $CLOG = "1" ]; then + log "$OOX" + fi +} + + +CURRMODEM=$1 + +MAN=$(uci get modem.modem$CURRMODEM.manuf) +MOD=$(uci get modem.modem$CURRMODEM.model) +$ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Connecting" +$ROOTER/log/logger "Attempting to Connect Modem #$CURRMODEM ($MAN $MOD)" + +BASEP=$(uci -q get modem.modem$CURRMODEM.baseport) +idV=$(uci get modem.modem$CURRMODEM.idV) +idP=$(uci get modem.modem$CURRMODEM.idP) + +$ROOTER/connect/get_profile.sh $CURRMODEM + +INTER=$(uci get modem.modeminfo$CURRMODEM.inter) +if [ -z $INTER ]; then + INTER=$CURRMODEM +else + if [ $INTER = 0 ]; then + INTER=$CURRMODEM + fi +fi +log "Profile for Modem $CURRMODEM sets interface to WAN$INTER" +OTHER=1 +if [ $CURRMODEM = 1 ]; then + OTHER=2 +fi +EMPTY=$(uci get modem.modem$OTHER.empty) +if [ $EMPTY = 0 ]; then + OINTER=$(uci get modem.modem$OTHER.inter) + if [ ! -z $OINTER ]; then + if [ $INTER = $OINTER ]; then + INTER=1 + if [ $OINTER = 1 ]; then + INTER=2 + fi + log "Switched Modem $CURRMODEM to WAN$INTER as Modem $OTHER is using WAN$OINTER" + fi + fi +fi +uci set modem.modem$CURRMODEM.inter=$INTER +uci commit modem +log "Modem $CURRMODEM is using WAN$INTER" + +log "Checking Network Interface" +MATCH="$(uci get modem.modem$CURRMODEM.maxcontrol | cut -d/ -f3- | xargs dirname)" +ifname="$(if [ "$MATCH" ]; then for a in /sys/class/net/*; do readlink $a; done | grep "$MATCH"; fi | xargs -r basename)" + +if [ "$ifname" ]; then + log "Modem $CURRMODEM - iPhone - Data Port : $ifname" + set_network "$ifname" + uci set modem.modem$CURRMODEM.interface=$ifname +else + log "Modem $CURRMODEM - No iPhone Data Port found" +fi +uci commit modem + +rm -f /tmp/usbwait + +ifup wan$INTER +while `ifstatus wan$INTER | grep -q '"up": false\|"pending": true'`; do + sleep 1 +done +wan_ip=$(expr "`ifstatus wan$INTER | grep '"nexthop":'`" : '.*"nexthop": "\(.*\)"') +if [ $? -ne 0 ] ; then + wan_ip=192.168.0.1 +fi +uci set modem.modem$CURRMODEM.ip=$wan_ip +uci commit modem + +log "saving Trusted locks" +for file in `ls /var/lib/lockdown | grep -v SystemConfiguration.plist`; +do + if [ ! -f "/etc/lockdown/locks/$file" ];then + cp /var/lib/lockdown/$file /etc/lockdown/locks/ + else + new_md5=`md5sum /var/lib/lockdown/$file | awk -F" " '{print $1}'` + old_md5=`md5sum /etc/lockdown/locks/$file | awk -F" " '{print $1}'` + if [ "$new_md5" != "$old_md5" ];then + cp /var/lib/lockdown/$file /etc/lockdown/locks/ + fi + fi +done + +$ROOTER/log/logger "iPhone #$CURRMODEM Connected with IP $wan_ip" + +ln -s $ROOTER/signal/otherhostless.sh $ROOTER_LINK/getsignal$CURRMODEM +$ROOTER_LINK/getsignal$CURRMODEM $CURRMODEM $PROT & + +ln -s $ROOTER/connect/conmon.sh $ROOTER_LINK/con_monitor$CURRMODEM +$ROOTER_LINK/con_monitor$CURRMODEM $CURRMODEM & +uci set modem.modem$CURRMODEM.connected=1 +uci commit modem + +if [ -e $ROOTER/timezone.sh ]; then + TZ=$(uci -q get modem.modeminfo$CURRMODEM.tzone) + if [ "$TZ" = "1" ]; then + log "Set TimeZone" + $ROOTER/timezone.sh & + fi +fi + +CLB=$(uci -q get modem.modeminfo$CURRMODEM.lb) +if [ -e /etc/config/mwan3 ]; then + ENB=$(uci -q get mwan3.wan$INTER.enabled) + if [ ! -z $ENB ]; then + if [ $CLB = "1" ]; then + uci set mwan3.wan$INTER.enabled=1 + else + uci set mwan3.wan$INTER.enabled=0 + fi + uci commit mwan3 + /usr/sbin/mwan3 restart + fi +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/disablemw3.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/disablemw3.sh new file mode 100644 index 0000000..9cef8b9 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/disablemw3.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +CURRMODEM=$1 + +if [ -e /etc/config/mwan3 ]; then + INTER=$(uci get modem.modeminfo$CURRMODEM.inter) + ENB=$(uci get mwan3.wan$INTER.enabled) + if [ ! -z $ENB ]; then + uci set mwan3.wan$INTER.enabled=0 + uci commit mwan3 + fi +fi \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/disconnect.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/disconnect.sh new file mode 100644 index 0000000..bde1749 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/disconnect.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" +TIMEOUT=10 + +log() { + modlog "Disconnect Modem $CURRMODEM" "$@" +} + +handle_timeout(){ + local wget_pid="$1" + local count=0 + res=1 + if [ -d /proc/${wget_pid} ]; then + res=0 + fi + while [ "$res" = 0 -a $count -lt "$((TIMEOUT))" ]; do + sleep 1 + count=$((count+1)) + res=1 + if [ -d /proc/${wget_pid} ]; then + res=0 + fi + done + + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill "$wget_pid" 2> /dev/null + res=1 + if [ -d /proc/${wget_pid} ]; then + res=0 + fi + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill -9 $wget_pid 2> /dev/null + fi + fi +} + +CURRMODEM=$(uci get modem.general.miscnum) +uci set modem.modem$CURRMODEM.connected=0 +uci commit modem +INTER=$(uci get modem.modeminfo$CURRMODEM.inter) + +jkillall getsignal$CURRMODEM +rm -f $ROOTER_LINK/getsignal$CURRMODEM +jkillall con_monitor$CURRMODEM +rm -f $ROOTER_LINK/con_monitor$CURRMODEM +ifdown wan$INTER + +MAN=$(uci get modem.modem$CURRMODEM.manuf) +MOD=$(uci get modem.modem$CURRMODEM.model) +$ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Disconnected" + +PROT=$(uci get modem.modem$CURRMODEM.proto) +CPORT=$(uci get modem.modem$CURRMODEM.commport) + +case $PROT in +"30" ) + ATCMDD="AT+CFUN=0" + $ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD" + ;; +"3" ) + WDMNX=$(uci get modem.modem$CURRMODEM.wdm) + umbim -n -t 3 -d /dev/cdc-wdm$WDMNX disconnect + ;; +* ) + $ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "reset.gcom" "$CURRMODEM" + ;; +esac + +$ROOTER/log/logger "Modem #$CURRMODEM was Manually Disconnected" diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/get_profile.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/get_profile.sh new file mode 100644 index 0000000..89c5194 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/get_profile.sh @@ -0,0 +1,423 @@ +#!/bin/sh + +. /lib/functions.sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "Get Profile $CURRMODEM" "$@" +} + +CURRMODEM=$1 + +MODEL=$(uci get modem.modem$CURRMODEM.model) +MANUF=$(uci get modem.modem$CURRMODEM.manuf) +idV=$(uci get modem.modem$CURRMODEM.idV) +idP=$(uci get modem.modem$CURRMODEM.idP) +IMEI=$(uci get modem.modem$CURRMODEM.imei) +IMSI=$(uci -q get modem.modem$CURRMODEM.imsi) +ICCID=$(uci get modem.modem$CURRMODEM.iccid) + +log "Modem $CURRMODEM is $MANUF $MODEL" + +rm -f /tmp/profile$CURRMODEM + +if [ "$IMSI" = "Unknown" ]; then + log "Warning: IMSI cannot be read - SIM card missing or locked?" + touch /tmp/simerr$CURRMODEM +else + rm -f /tmp/simerr$CURRMODEM +fi + +MATCH=0 + +do_custom() { + local config=$1 + local select name enabled select1 + local model + local imsi + local vid + local pid + + if [ $MATCH -eq 0 ]; then + config_get select $1 select + config_get name $1 name + config_get enabled $1 enabled + if [ -z "$enabled" ]; then + enabled=1 + fi + if [ -z "$name" ]; then + name="Not Named" + fi + if [ $enabled -eq 1 ]; then + case $select in + "0" ) + config_get vid $1 vid + config_get pid $1 pid + if [ $idV = $vid -a $idP = $pid ]; then + MATCH=1 + log "Modem ID Profile - "$name"" + fi + ;; + "1" ) + config_get imei $1 imei + case $IMEI in + "$imei"*) + MATCH=1 + log "SIM IMEI Profile - "$name"" + ;; + esac + ;; + "2" ) + config_get model $1 model + if [ "$MODEL" == "$model" ]; then + MATCH=1 + log "Modem Model Profile - "$name"" + fi + ;; + "3" ) + config_get imsi $1 imsi + case $IMSI in + "$imsi"*) + MATCH=1 + log "SIM IMSI Profile - "$name"" + ;; + esac + ;; + "4" ) + config_get iccid $1 iccid + case $ICCID in + "$iccid"*) + MATCH=1 + log "SIM ICCID Profile - "$name"" + ;; + esac + ;; + esac + if [ $MATCH = 1 ]; then + config_get select1 $1 select1 + if [ $select1 -ne 10 ]; then + MATCH=0 + case $select1 in + "0" ) + config_get vid1 $1 vid1 + config_get pid1 $1 pid1 + if [ $idV = $vid1 -a $idP = $pid1 ]; then + MATCH=1 + log "Modem ID Profile - "$name"" + fi + ;; + "1" ) + config_get imei1 $1 imei1 + case $IMEI in + "$imei"*) + MATCH=1 + log "SIM IMEI Profile - "$name"" + ;; + esac + ;; + "2" ) + config_get model1 $1 model1 + if [ "$MODEL" == "$model1" ]; then + MATCH=1 + log "Modem Model Profile - "$name"" + fi + ;; + "3" ) + config_get imsi1 $1 imsi1 + case $IMSI in + "$imsi1"*) + MATCH=1 + log "SIM IMSI Profile - "$name"" + ;; + esac + ;; + "4" ) + config_get iccid1 $1 iccid1 + case $ICCID in + "$iccid1"*) + MATCH=1 + log "SIM ICCID Profile - "$name"" + ;; + esac + ;; + esac + fi + if [ $MATCH = 1 ]; then + local apn user passw pincode auth ppp delay lock mcc mnc + local dns1 dns2 dns3 dns4 log lb at atc + config_get apn $1 apn + dapn=$(echo "$apn" | grep "|") + if [ -z $dapn ]; then + apn2="" + else + fapn=$apn"|" + fapn=$(echo $fapn" " | tr "|" ",") + apn=$(echo $fapn | cut -d, -f1) + apn2=$(echo $fapn | cut -d, -f2) + fi + uci set modem.modeminfo$CURRMODEM.apn=$apn + uci set modem.modeminfo$CURRMODEM.apn2=$apn2 + config_get mtu $1 mtu + uci set modem.modeminfo$CURRMODEM.mtu=$mtu + config_get context $1 context + uci set modem.modeminfo$CURRMODEM.context=$context + config_get user $1 user + uci set modem.modeminfo$CURRMODEM.user=$user + config_get passw $1 passw + uci set modem.modeminfo$CURRMODEM.passw=$passw + config_get pincode $1 pincode + uci set modem.modeminfo$CURRMODEM.pincode=$pincode + config_get auth $1 auth + uci set modem.modeminfo$CURRMODEM.auth=$auth + config_get ppp $1 ppp + uci set modem.modeminfo$CURRMODEM.ppp=$ppp + config_get inter $1 inter + uci set modem.modeminfo$CURRMODEM.inter=$inter + config_get delay $1 delay + uci set modem.modeminfo$CURRMODEM.delay=$delay + config_get lock $1 lock + uci set modem.modeminfo$CURRMODEM.lock=$lock + config_get mcc $1 mcc + uci set modem.modeminfo$CURRMODEM.mcc=$mcc + config_get mnc $1 mnc + uci set modem.modeminfo$CURRMODEM.mnc=$mnc + config_get dns1 $1 dns1 + uci set modem.modeminfo$CURRMODEM.dns1=$dns1 + config_get dns2 $1 dns2 + uci set modem.modeminfo$CURRMODEM.dns2=$dns2 + config_get dns3 $1 dns3 + uci set modem.modeminfo$CURRMODEM.dns3=$dns3 + config_get dns4 $1 dns4 + uci set modem.modeminfo$CURRMODEM.dns4=$dns4 + config_get log $1 log + uci set modem.modeminfo$CURRMODEM.log=$log + config_get lb $1 lb + uci set modem.modeminfo$CURRMODEM.lb=$lb + config_get at $1 at + uci set modem.modeminfo$CURRMODEM.at=$at + config_get atc $1 atc + uci set modem.modeminfo$CURRMODEM.atc=$atc + config_get tzone $1 tzone + uci set modem.modeminfo$CURRMODEM.tzone=$tzone + config_get nodhcp $1 nodhcp + uci set modem.modeminfo$CURRMODEM.nodhcp=$nodhcp + config_get pdptype $1 pdptype + if [ $pdptype = "0" ]; then + pdptype="" + fi + uci set modem.modeminfo$CURRMODEM.pdptype=$pdptype + config_get ttl $1 ttl + if [ -z "$ttl" ]; then + ttl="0" + fi + uci set modem.modeminfo$CURRMODEM.ttl="$ttl" + config_get hostless $1 hostless + if [ -z "$hostless" ]; then + hostless="0" + fi + uci set modem.modeminfo$CURRMODEM.hostless="$hostless" + config_get bwday $1 bwday + if [ -z $bwday ]; then + bwday="0" + fi + uci set modem.modeminfo$CURRMODEM.bwday=$bwday + config_get phone $1 phone + if [ -z $phone ]; then + phone="0" + fi + uci set modem.modeminfo$CURRMODEM.bwphone=$phone + config_get bwdelay $1 bwdelay + if [ -z $bwdelay ]; then + bwdelay="0" + fi + uci set modem.modeminfo$CURRMODEM.bwdelay=$bwdelay + + [ -n "$apn" ] || log "This profile has no APN configured !!!" + + config_get alive $1 alive + uci delete modem.pinginfo$CURRMODEM + uci set modem.pinginfo$CURRMODEM=pinfo$CURRMODEM + uci set modem.pinginfo$CURRMODEM.alive=$alive + if [ $alive -ne 0 ]; then + local reliability count pingtime pingwait packetsize down up + + handle_trackip() { + local value="$1" + uci add_list modem.pinginfo$CURRMODEM.trackip=$value + } + config_list_foreach "$config" trackip handle_trackip + TIP=$(uci get modem.pinginfo$CURRMODEM.trackip) + if [ -z "$TIP" ]; then + uci add_list modem.pinginfo$CURRMODEM.trackip="1.1.1.1" + fi + config_get reliability $1 reliability + uci set modem.pinginfo$CURRMODEM.reliability=$reliability + config_get count $1 count + uci set modem.pinginfo$CURRMODEM.count=$count + config_get pingtime $1 pingtime + uci set modem.pinginfo$CURRMODEM.pingtime=$pingtime + config_get pingwait $1 pingwait + uci set modem.pinginfo$CURRMODEM.pingwait=$pingwait + config_get packetsize $1 packetsize + uci set modem.pinginfo$CURRMODEM.packetsize=$packetsize + config_get down $1 down + uci set modem.pinginfo$CURRMODEM.down=$down + config_get up $1 up + uci set modem.pinginfo$CURRMODEM.up=$up + fi + + uci commit modem + fi + fi + fi + fi +} + +autoapn=$(uci -q get profile.disable.autoapn) +apd=0 +if [ -e /usr/lib/autoapn/apn.data ]; then + apd=1 +fi + +if [ $autoapn = "1" -a $apd -eq 1 ]; then + MATCH=0 +else + autod=$(uci -q get profile.disable.enabled) + if [ $autod = "1" ]; then + MATCH=0 + else + config_load profile + config_foreach do_custom custom + fi +fi + +if [ $MATCH = 0 ]; then + if [ $autod = "1" ]; then + if [ -e /etc/config/isp ]; then + MATCH=1 + fi + fi + if [ $MATCH = 1 ]; then + isp=$(uci -q get isp.general.current) + apn=$(uci -q get isp.$isp.apn) + apn2="" + else + apn=$(uci -q get profile.default.apn) + dapn=$(echo "$apn" | grep "|") + if [ -z $dapn ]; then + apn2="" + else + fapn=$apn"|" + fapn=$(echo $fapn" " | tr "|" ",") + apn=$(echo $fapn | cut -d, -f1) + apn2=$(echo $fapn | cut -d, -f2) + fi + fi + uci set modem.modeminfo$CURRMODEM.apn=$apn + uci set modem.modeminfo$CURRMODEM.apn2=$apn2 + if [ -n "$ICCID" ]; then + iccid="891490" + case $ICCID in + "$iccid"*) + uci set modem.modeminfo$CURRMODEM.apn2="" + uci set modem.modeminfo$CURRMODEM.apn="internet.freedommobile.ca" + ;; + esac + fi + + uci set modem.modeminfo$CURRMODEM.user=$(uci -q get profile.default.user) + uci set modem.modeminfo$CURRMODEM.passw=$(uci -q get profile.default.passw) + uci set modem.modeminfo$CURRMODEM.pincode=$(uci -q get profile.default.pincode) + uci set modem.modeminfo$CURRMODEM.context=$(uci -q get profile.default.context) + uci set modem.modeminfo$CURRMODEM.auth=$(uci get profile.default.auth) + uci set modem.modeminfo$CURRMODEM.ppp=$(uci get profile.default.ppp) + uci set modem.modeminfo$CURRMODEM.inter=0 + uci set modem.modeminfo$CURRMODEM.delay=$(uci get profile.default.delay) + uci set modem.modeminfo$CURRMODEM.lock=$(uci get profile.default.lock) + uci set modem.modeminfo$CURRMODEM.mcc=$(uci -q get profile.default.mcc) + uci set modem.modeminfo$CURRMODEM.mnc=$(uci -q get profile.default.mnc) + uci set modem.modeminfo$CURRMODEM.dns1=$(uci -q get profile.default.dns1) + uci set modem.modeminfo$CURRMODEM.dns2=$(uci -q get profile.default.dns2) + uci set modem.modeminfo$CURRMODEM.dns3=$(uci -q get profile.default.dns3) + uci set modem.modeminfo$CURRMODEM.dns4=$(uci -q get profile.default.dns4) + uci set modem.modeminfo$CURRMODEM.log=$(uci get profile.default.log) + uci set modem.modeminfo$CURRMODEM.lb=$(uci get profile.default.lb) + uci set modem.modeminfo$CURRMODEM.at=$(uci -q get profile.default.at) + uci set modem.modeminfo$CURRMODEM.atc=$(uci -q get profile.default.atc) + uci set modem.modeminfo$CURRMODEM.tzone=$(uci -q get profile.default.tzone) + uci set modem.modeminfo$CURRMODEM.mtu=$(uci -q get profile.default.mtu) + uci set modem.modeminfo$CURRMODEM.nodhcp=$(uci -q get profile.default.nodhcp) + pdp=$(uci -q get profile.default.pdptype) + if [ $pdp = "0" ]; then + pdp="" + fi + uci set modem.modeminfo$CURRMODEM.pdptype=$pdp + ttl=$(uci -q get profile.default.ttl) + if [ -z "$ttl" ]; then + ttl="0" + fi + uci set modem.modeminfo$CURRMODEM.ttl="$ttl" + hostless=$(uci -q get profile.default.hostless) + if [ -z "$hostless" ]; then + hostless="0" + fi + uci set modem.modeminfo$CURRMODEM.hostless="$hostless" + bwday=$(uci -q get profile.default.bwday) + if [ -z $bwday ]; then + bwday="0" + fi + uci set modem.modeminfo$CURRMODEM.bwday=$bwday + phone=$(uci -q get profile.default.phone) + if [ -z $phone ]; then + phone="0" + fi + uci set modem.modeminfo$CURRMODEM.bwphone=$phone + bwdelay=$(uci -q get profile.default.bwdelay) + if [ -z $bwdelay ]; then + bwdelay="0" + fi + uci set modem.modeminfo$CURRMODEM.bwdelay=$bwdelay + + alive=$(uci get profile.default.alive) + uci delete modem.pinginfo$CURRMODEM + uci set modem.pinginfo$CURRMODEM=pinfo$CURRMODEM + uci set modem.pinginfo$CURRMODEM.alive=$alive + if [ $alive -ne 0 ]; then + + handle_trackip1() { + local value="$1" + uci add_list modem.pinginfo$CURRMODEM.trackip=$value + } + config_list_foreach "default" trackip handle_trackip1 + TIP=$(uci get modem.pinginfo$CURRMODEM.trackip) + if [ -z "$TIP" ]; then + uci add_list modem.pinginfo$CURRMODEM.trackip="1.1.1.1" + fi + uci set modem.pinginfo$CURRMODEM.reliability=$(uci get profile.default.reliability) + uci set modem.pinginfo$CURRMODEM.count=$(uci get profile.default.count) + uci set modem.pinginfo$CURRMODEM.pingtime=$(uci get profile.default.pingtime) + uci set modem.pinginfo$CURRMODEM.pingwait=$(uci get profile.default.pingwait) + uci set modem.pinginfo$CURRMODEM.packetsize=$(uci get profile.default.packetsize) + uci set modem.pinginfo$CURRMODEM.down=$(uci get profile.default.down) + uci set modem.pinginfo$CURRMODEM.up=$(uci get profile.default.up) + fi + + uci commit modem + if [ "$autoapn" = "1" -a $apd -eq 1 ]; then + log "Automatic APN Used" + else + log "Default Profile Used" + [ -n "$(uci -q get profile.default.apn)" ] || log "Default profile has no APN configured" + fi +fi + +if [ ! -e /etc/config/isp ]; then + if [ "$autoapn" != "1" -a $apd -eq 1 ]; then + APN=$(uci -q get modem.modeminfo$CURRMODEM.apn) + log "APN of profile used is $APN" + fi +fi + +touch /tmp/profile$CURRMODEM diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/handlettl.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/handlettl.sh new file mode 100644 index 0000000..fe216c6 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/handlettl.sh @@ -0,0 +1,106 @@ +#!/bin/sh + +log() { + modlog "TTL Settings $CURRMODEM" "$@" +} + +delTTL() { + FLG="0" + exst=$(cat /etc/ttl.user | grep "#startTTL$CURRMODEM") + if [ ! -z "$exst" ]; then + cp /etc/ttl.user /etc/ttl.user.bk + sed -i -e "s!iptables -t mangle -I POSTROUTING -o $IFACE!iptables -t mangle -D POSTROUTING -o $IFACE!g" /etc/ttl.user.bk + sed -i -e "s!iptables -t mangle -I PREROUTING -i $IFACE!iptables -t mangle -D PREROUTING -i $IFACE!g" /etc/ttl.user.bk + sed -i -e "s!ip6tables -t mangle -I POSTROUTING -o $IFACE!iptables -t mangle -D POSTROUTING -o $IFACE!g" /etc/ttl.user.bk + sed -i -e "s!ip6tables -t mangle -I PREROUTING -i $IFACE!iptables -t mangle -D PREROUTING -i $IFACE!g" /etc/ttl.user.bk + + rm -f /tmp/ttl.user + run=0 + while IFS= read -r line; do + if [ $run = "0" ]; then + sttl=$line + stx=$(echo "$sttl" | grep "#startTTL$CURRMODEM") + if [ ! -z $stx ]; then + run=1 + fi + else + sttl=$line + stx=$(echo "$sttl" | grep "#endTTL$CURRMODEM") + if [ ! -z $stx ]; then + chmod 777 /tmp/ttl.user + /tmp/ttl.user + break + fi + echo "$sttl" >> /tmp/ttl.user + fi + done < /etc/ttl.user.bk + cp /etc/ttl.user /etc/ttl.user.bk + + sed /"#startTTL$CURRMODEM"/,/"#endTTL$CURRMODEM"/d /etc/ttl.user.bk > /etc/ttl.user + FLG="1" + fi +} + +CURRMODEM=$1 +TTL="$2" +if [ $CURRMODEM = "0" ]; then + IFACE="wan" +else + IFACE=$(uci -q get modem.modem$CURRMODEM.interface) +fi + +if [ "$TTL" = "0" ]; then + ENB=$(uci -q get ttl.ttl.enabled) + if [ $ENB = "1" ]; then + TTL=$(uci -q get ttl.ttl.value) + if [ -z "$TTL" ]; then + TTL=65 + fi + else + delTTL + log "Deleting TTL on interface $IFACE" + exit 0 + fi +fi + +if [ "$TTL" = "1" ]; then + delTTL + log "Deleting TTL on interface $IFACE" + exit 0 +fi + +delTTL +VALUE="$TTL" +echo "#startTTL$CURRMODEM" >> /etc/ttl.user +log "Setting TTL $VALUE on interface $IFACE" +if [ "$TTL" = "TTL-INC 1" ]; then + TTL="0" +fi + +if [ $VALUE = "0" ]; then + echo "iptables -t mangle -I POSTROUTING -o $IFACE -j TTL --ttl-inc 1" >> /etc/ttl.user + echo "iptables -t mangle -I PREROUTING -i $IFACE -j TTL --ttl-inc 1" >> /etc/ttl.user + iptables -t mangle -I POSTROUTING -o $IFACE -j TTL --ttl-inc 1 + iptables -t mangle -I PREROUTING -i $IFACE -j TTL --ttl-inc 1 + if [ -e /usr/sbin/ip6tables ]; then + echo "ip6tables -t mangle -I POSTROUTING -o $IFACE -j HL --hl-inc 1" >> /etc/ttl.user + echo "ip6tables -t mangle -I PREROUTING -i $IFACE -j HL --hl-inc 1" >> /etc/ttl.user + ip6tables -t mangle -I POSTROUTING -o $IFACE -j HL --hl-inc 1 + ip6tables -t mangle -I PREROUTING -i $IFACE -j HL --hl-inc 1 + fi +else + echo "iptables -t mangle -I POSTROUTING -o $IFACE -j TTL --ttl-set $VALUE" >> /etc/ttl.user + echo "iptables -t mangle -I PREROUTING -i $IFACE -j TTL --ttl-set $VALUE" >> /etc/ttl.user + iptables -t mangle -I POSTROUTING -o $IFACE -j TTL --ttl-set $VALUE + iptables -t mangle -I PREROUTING -i $IFACE -j TTL --ttl-set $VALUE + if [ -e /usr/sbin/ip6tables ]; then + echo "ip6tables -t mangle -I POSTROUTING -o $IFACE -j HL --hl-set $VALUE" >> /etc/ttl.user + echo "ip6tables -t mangle -I PREROUTING -i $IFACE -j HL --hl-set $VALUE" >> /etc/ttl.user + ip6tables -t mangle -I POSTROUTING -o $IFACE -j HL --hl-set $VALUE + ip6tables -t mangle -I PREROUTING -i $IFACE -j HL --hl-set $VALUE + fi +fi +echo "#endTTL$CURRMODEM" >> /etc/ttl.user + + + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/postconnect.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/postconnect.sh new file mode 100644 index 0000000..12ec93e --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/postconnect.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "PostConnect $CURRMODEM" "$@" +} + +CURRMODEM=$1 +idV=$(uci -q get modem.modem$CURRMODEM.idV) +idP=$(uci -q get modem.modem$CURRMODEM.idP) +CPORT=$(uci get modem.modem$CURRMODEM.commport) + +log "Running PostConnect script" + +if [ -e /usr/lib/scan/emailchk.sh ]; then + /usr/lib/scan/emailchk.sh & +fi \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/preconnect.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/preconnect.sh new file mode 100644 index 0000000..92bef6f --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/preconnect.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "PreConnect $CURRMODEM" "$@" +} + +CURRMODEM=$1 +idV=$(uci -q get modem.modem$CURRMODEM.idV) +idP=$(uci -q get modem.modem$CURRMODEM.idP) +CPORT=$(uci get modem.modem$CURRMODEM.commport) + +log "Running PreConnect script" \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/reconnect-ppp.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/reconnect-ppp.sh new file mode 100644 index 0000000..26e6ccf --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/reconnect-ppp.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + logger -t "Reconnect Modem" "$@" +} + +CURRMODEM=$1 +uci set modem.modem$CURRMODEM.connected=0 +uci commit modem + +INTER=$(uci get modem.modeminfo$CURRMODEM.inter) + +jkillall getsignal$CURRMODEM +rm -f $ROOTER_LINK/getsignal$CURRMODEM +jkillall con_monitor$CURRMODEM +rm -f $ROOTER_LINK/con_monitor$CURRMODEM +ifdown wan$INTER +MAN=$(uci get modem.modem$CURRMODEM.manuf) +MOD=$(uci get modem.modem$CURRMODEM.model) +$ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Reconnecting" +PROT=$(uci get modem.modem$CURRMODEM.proto) + +CPORT=$(uci get modem.modem$CURRMODEM.commport) + +SEVR=$(uci get modem.modem$CURRMODEM.service) + +if [ $SEVR = 0 ]; then + COUNTER=1 + while [ $COUNTER -lt 6 ]; do + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "reset.gcom" "$CURRMODEM") + ERROR="ERROR" + if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` + then + log "Retry Reset" + sleep 3 + let COUNTER=COUNTER+1 + else + log "Modem Reset" + sleep 3 + $ROOTER/common/lockchk.sh $CURRMODEM + break + fi + done + if [ $COUNTER -lt 6 ]; then + ifup wan$INTER + else + log "Reset Failed for Modem $CURRMODEM" + $ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Failed to Reset" + fi +else + ifup wan$INTER +fi + + + + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/reconnect.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/reconnect.sh new file mode 100644 index 0000000..98ba291 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/connect/reconnect.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +ROOTER_LINK="/tmp/links" + +log() { + modlog "Reconnect Modem $CURRMODEM" "$@" +} + +CURRMODEM=$1 +log "Re-starting Connection for Modem $CURRMODEM" +$ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM 1 + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/customname.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/customname.lua new file mode 100644 index 0000000..464217d --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/customname.lua @@ -0,0 +1,17 @@ +#!/usr/bin/lua + +mfile = "/tmp/sysinfo/model" +nfile="/etc/custom" +local file = io.open(nfile, "r") +if file == nil then + return +end +linex = file:read("*line") +file:close() +file = io.open(mfile, "w") +if file == nil then + return +end + +file:write(linex,"\n") +file:close() \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/auto.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/auto.gcom new file mode 100644 index 0000000..73544d9 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/auto.gcom @@ -0,0 +1,31 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT!SCPROF?1^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s +:continue +exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult + print $s + return diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/baseinfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/baseinfo.gcom new file mode 100644 index 0000000..84149d6 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/baseinfo.gcom @@ -0,0 +1,33 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 1 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "ATI^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CGEQNEG=1^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cellinfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cellinfo.gcom new file mode 100644 index 0000000..6ced05d --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cellinfo.gcom @@ -0,0 +1,50 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CREG=2;+CREG?;+CREG=0^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CEREG=2;+CEREG?;+CEREG=0^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+C5GREG=2;+C5GREG?;+C5GREG=0^m" +let t=time()+f +gosub noerror +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult + +:noerror +get 1 "^m" $s +if $mid($s,0,6)="^jERROR" return +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto noerror diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cellinfo0.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cellinfo0.gcom new file mode 100644 index 0000000..4a72dd0 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cellinfo0.gcom @@ -0,0 +1,45 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+COPS=3,0;+COPS?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+COPS=3,2;+COPS?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult + +:noerror +get 1 "^m" $s +if $mid($s,0,6)="^jERROR" return +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto noerror diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cgpaddr.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cgpaddr.gcom new file mode 100644 index 0000000..126aef6 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/cgpaddr.gcom @@ -0,0 +1,46 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CGPADDR=1^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^SYSINFOEX^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^SYSINFO^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^NDISSTATQRY?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-directip.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-directip.gcom new file mode 100644 index 0000000..00bc9e4 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-directip.gcom @@ -0,0 +1,64 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT!SCACT=0,1^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT!SCDFTPROF=1^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +let $x=$env("SETAPN") +let $y=$env("SETUSER") +let $z=$env("SETPASS") +let $a=$env("SETAUTH") +send "AT+CGDCONT=1,\"IP\",\"" +send $x +send "\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT$QCPDPP=1," +send $a +if $a="0" send "^m" +else send ",\"" send $z send "\",\"" send $y send "\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT!SCACT=1,1^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT!SCACT?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-fecm.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-fecm.gcom new file mode 100644 index 0000000..653f601 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-fecm.gcom @@ -0,0 +1,45 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+GTRNDIS=0,1" +send "^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +let $x=$env("SETAPN") +send "AT+CGDCONT=1,\"IP\",\"" +send $x +send "\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+GTRNDIS=1,1" +send "^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-ncm.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-ncm.gcom new file mode 100644 index 0000000..1fd4893 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-ncm.gcom @@ -0,0 +1,48 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT^^NDISDUP=1,0^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +let $x=$env("SETAPN") +let $y=$env("SETUSER") +let $z=$env("SETPASS") +let $a=$env("SETAUTH") +send "AT^^NDISDUP=1,1,\"" +send $x +if $a="0" send "\"^m" +else send "\",\"" send $y send "\",\"" send $z send "\"," send $a send "^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^NDISSTATQRY?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-ppp.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-ppp.gcom new file mode 100644 index 0000000..fadf2d8 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-ppp.gcom @@ -0,0 +1,36 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +let $y=$env("SETUSER") +let $z=$env("SETPASS") +let $a=$env("SETAUTH") +send "AT$QCPDPP=1," +send $a +if $a="0" send "^m" +else send ",\"" send $z send "\",\"" send $y send "\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-zecm.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-zecm.gcom new file mode 100644 index 0000000..fd14d94 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/connect-zecm.gcom @@ -0,0 +1,45 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+ZECMCALL=0" +send "^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +let $x=$env("SETAPN") +send "AT+CGDCONT=1,\"IP\",\"" +send $x +send "\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+ZECMCALL=1" +send "^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/curc.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/curc.gcom new file mode 100644 index 0000000..59f79da --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/curc.gcom @@ -0,0 +1,31 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT\^CURC=0^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/fibocominfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/fibocominfo.gcom new file mode 100644 index 0000000..72126b5 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/fibocominfo.gcom @@ -0,0 +1,65 @@ +opengt +set com 115200n81 +set comecho off +set senddelay 0.02 +waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+GTCCINFO?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s +if $s="^jERROR" goto gtrat + +send "AT+COPN^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:gtrat +send "AT+GTRAT?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+GTCAINFO?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+XACT?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+XMCI=1;+XLEC?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+MTSM=1^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/gcom-locked b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/gcom-locked new file mode 100644 index 0000000..ff816e2 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/gcom-locked @@ -0,0 +1,41 @@ +#!/bin/sh + +log() { + logger -t "gcom-locked " "$@" +} + +ROOTER_GCOM="/usr/lib/rooter/gcom/" + + +PORT=$1 +GCOM=$2 +CURRMODEM=$3 +ATC=$4 + +LOCKDIR="/tmp/lockgcom$CURRMODEM" +PIDFILE="${LOCKDIR}/PID" + +while [ 1 -lt 6 ]; do + if mkdir "${LOCKDIR}" &>/dev/null; then + echo "$$" > "${PIDFILE}" + if [ ! -z "$ATC" ]; then + export ATCMD="$ATC" + fi + OX=$(gcom -d $PORT -s $ROOTER_GCOM$GCOM 2>/dev/null) + if [ ! -e /tmp/block ]; then + /usr/lib/rooter/log/at-logger "$PORT $OX" + fi + break + else + OTHERPID="$(cat "${PIDFILE}" 2>/dev/null)" + if [ $? = 0 ]; then + if ! kill -0 $OTHERPID &>/dev/null; then + rm -rf "${LOCKDIR}" + fi + fi + sleep 1 + fi +done + +rm -rf "${LOCKDIR}" +echo "$OX" \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/gettype.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/gettype.gcom new file mode 100644 index 0000000..77d733b --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/gettype.gcom @@ -0,0 +1,43 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CFUN=1^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "ATI^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CNUM^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CPBR=?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/huaweiinfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/huaweiinfo.gcom new file mode 100644 index 0000000..cd9a091 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/huaweiinfo.gcom @@ -0,0 +1,74 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^CSNR?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^HCSQ?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^SYSINFOEX^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^SYSCFGEX?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^SYSCFG?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^SYSINFO^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^HFREQINFO?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^LTERSRP?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^CHIPTEMP?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/lock-prov.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/lock-prov.gcom new file mode 100644 index 0000000..332890a --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/lock-prov.gcom @@ -0,0 +1,38 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+COPS=0^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +let $x=$env("MCCMNC") +send "AT+COPS=1,2,\"" +send $x +send "\",2^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/mdm9215info.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/mdm9215info.gcom new file mode 100644 index 0000000..a647dac --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/mdm9215info.gcom @@ -0,0 +1,43 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+COPS?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT$QCSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT$QCSYSMODE?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/meiginfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/meiginfo.gcom new file mode 100644 index 0000000..556874f --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/meiginfo.gcom @@ -0,0 +1,69 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+PSRAT^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +if $s="^jERROR" goto newmodel + +send "AT+MODODR?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CELLINFO^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+SGCELLINFO^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +exit 0 + +:newmodel + +send "AT\^SYSCFGEX?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+SGCELLINFOEX^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CELLINFO=3^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/novatelinfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/novatelinfo.gcom new file mode 100644 index 0000000..e1a58e8 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/novatelinfo.gcom @@ -0,0 +1,48 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT$NWRAT?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT$NWDEGC^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+VZWRSRP?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+VZWRSRQ?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/otherinfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/otherinfo.gcom new file mode 100644 index 0000000..6f851cd --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/otherinfo.gcom @@ -0,0 +1,28 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/quantainfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/quantainfo.gcom new file mode 100644 index 0000000..2ae0303 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/quantainfo.gcom @@ -0,0 +1,38 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT*QRFINFO?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^QCNCFG?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/quectelinfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/quectelinfo.gcom new file mode 100644 index 0000000..286acb9 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/quectelinfo.gcom @@ -0,0 +1,76 @@ +opengt +set com 115200n81 +set comecho off +set senddelay 0.02 +waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+QENG=\"servingcell\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+QRSRP^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+QCAINFO^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+QCFG=\"nwscanmode\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s +if $s="^jERROR" goto qnwpref +goto temp + +:qnwpref +send "AT+QNWPREFCFG=\"mode_pref\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:temp +send "AT+QTEMP^m" +let t=time()+1 +gosub gettemp + +send "AT+QENG=\"neighbourcell\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult + +:gettemp +get 1 "^m" $s +let x=len($s) +if x>0 print $s +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto gettemp diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/raw-ip.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/raw-ip.gcom new file mode 100644 index 0000000..cbdbf3e --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/raw-ip.gcom @@ -0,0 +1,31 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +let $x=$env("ATCMD") +send $x +send "^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jCONNECT" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/reset.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/reset.gcom new file mode 100644 index 0000000..09e46f5 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/reset.gcom @@ -0,0 +1,25 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +//send "ate0^m" +//waitquiet 1 0.2 +send "AT+COPS=2;+CFUN=4^m" +waitfor 5 "OK" +sleep 5 +send "AT+CFUN?^m" +waitfor 5 "+CME ERROR:","+CFUN:" +if % = 0 goto cme_err +get 2 " " $s +if $left($s,1) = "1" goto end +sleep 5 +send "AT+CFUN=1^m" +waitquiet 1 0.2 +exit 0 + +:cme_err +print "+CME ERROR" +:end +exit 0 diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/run-at.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/run-at.gcom new file mode 100644 index 0000000..b40dd6e --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/run-at.gcom @@ -0,0 +1,31 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g="" let f=25 +else let f=val($g) + +let $x=$env("ATCMD") +send $x +send "^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s +:continue +exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/sendsms-at.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/sendsms-at.gcom new file mode 100644 index 0000000..7203af5 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/sendsms-at.gcom @@ -0,0 +1,45 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start + +let $x=$env("ATCMD") +let $j=$left($x,1) +if $j = "0" let $j=$mid($x,1,2) +else let $j=$left($x,3) +let $r=$mid($x,4,4) +let k=len($x)-9 +let $p=$right($x,k) +send "AT+CMGF=0^m" +waitfor 2 "OK" +send "AT+CMGS=" +send $j +send "^m" +waitfor 3 ">" +send $p +send "^z" +waitfor 20 "+CMGS:" + +if % = 0 gosub sentsub +else gosub failsub + +get 1 "" $s + +:continue + exit 0 + +:sentsub +get 2 "^m^j" $s +let $c=$s +print "SMS sent, reference: "+$c +let $c='echo "SMS sent, reference: "'+$c+' > /tmp/smssendstatus'+$r +system $c +return + +:failsub +system 'echo "SMS sending failed" > /tmp/smssendstatus'+$r +print "SMS sending failed" +return diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/setapn.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/setapn.gcom new file mode 100644 index 0000000..9b29c50 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/setapn.gcom @@ -0,0 +1,45 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +let $x=$env("SETAPN") +let $y=$env("SETUSER") +let $z=$env("SETPASS") +let $a=$env("SETAUTH") +send "AT+CGDCONT=1,\"IP\",\"" +send $x +send "\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT$QCPDPP=1," +send $a +if $a="0" send "^m" +else send ",\"" send $z send "\",\"" send $y send "\"^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/setpin.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/setpin.gcom new file mode 100644 index 0000000..9084557 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/setpin.gcom @@ -0,0 +1,53 @@ +# set pin code from evnironment "$PINCODE" +opengt + set com 115200n81 + set senddelay 0.05 + waitquiet 3 0.5 + flash 0.1 + + let c=0 +:start + send "AT+CPIN?^m" + waitfor 15 "SIM PUK","SIM PIN","READY","ERROR","ERR" + if % = -1 goto timeout + if % = 0 goto ready + if % = 1 goto setpin + if % = 2 goto ready + if % = 3 goto checkrepeat + if % = 4 goto checkrepeat + +:checkrepeat + inc c + if c>3 goto pinerror + waitquiet 12 0.5 + goto start + +:timeout + print "ERROR" + exit 1 + +:ready + goto continue + exit 0 + +:setpin + # check if output was "SIM PIN2", that's ok. + waitfor 1 "2" + if % = 0 goto ready + + send "AT+CPIN=\"" + send $env("PINCODE") + send "\"^m" + + waitfor 20 "OK","ERR" + if % = -1 goto pinerror + if % = 0 goto continue + if % = 1 goto pinerror + +:pinerror + print "ERROR" + exit 1 + +:continue + print "OK" + exit 0 diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/sierrainfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/sierrainfo.gcom new file mode 100644 index 0000000..e24780c --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/sierrainfo.gcom @@ -0,0 +1,68 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ;+CESQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT*CNTI=0^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT!SELRAT?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+ECIO?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+RSCP?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT!UMTSCHAN?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT!LTEINFO?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT!GSTATUS?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT!PCTEMP?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/simcominfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/simcominfo.gcom new file mode 100644 index 0000000..50e45c9 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/simcominfo.gcom @@ -0,0 +1,48 @@ +opengt +set com 115200n81 +set comecho off +set senddelay 0.02 +waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CPSI?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CNMP?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CMGRMI=4^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CPMUTEMP^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/smschk.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/smschk.gcom new file mode 100644 index 0000000..f5d9e82 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/smschk.gcom @@ -0,0 +1,36 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CMGS=?;+CMGL=?;+CMGR=?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send 'AT+CPMS="SM","SM","SM"^m' +waitfor 5 "OK" + +send 'AT+CGSMS=2^m' +waitfor 5 "OK" + +:continue + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/smswrite.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/smswrite.gcom new file mode 100644 index 0000000..a65bb3c --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/smswrite.gcom @@ -0,0 +1,39 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 + +:start + +let $x=$env("ATCMD") +let $j=$left($x,1) +if $j = "0" let $j=$mid($x,1,2) +else let $j=$left($x,3) +let $d=$mid($x,4,2) +let $t=$mid($x,7,1) +let k=len($x)-9 +let $p=$right($x,k) +send "AT+CMGF=0^m" +waitfor 2 "OK" +send 'AT+CPMS="SM"' +send ',"' +send $d +send '"^m' +waitfor 2 "OK" +send "AT+CMGW=" +send $j +send "," +send $t +send "^m" +waitfor 3 ">" +send $p +send "^z" +waitfor 25 "+CMGW:" +if % = 0 print "+CMGW:" +else print "AT+CMGW - TIMEOUT" +get 1 "" $s +print $s + +:continue + exit 0 diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/t77info.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/t77info.gcom new file mode 100644 index 0000000..f47d378 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/t77info.gcom @@ -0,0 +1,70 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+COPS?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^CA_INFO?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^DEBUG?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT$DEBUG?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT\^SYSCONFIG?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT$QCSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+TEMP?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +if $s!="^jERROR" exit 0 + +send "AT\^TEMP?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/telitinfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/telitinfo.gcom new file mode 100644 index 0000000..5eaff94 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/telitinfo.gcom @@ -0,0 +1,48 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT#TEMPSENS=2^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+COPS?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT#RFSTS^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT#CAINFO?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/telitinfoln.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/telitinfoln.gcom new file mode 100644 index 0000000..eb9bcbd --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/telitinfoln.gcom @@ -0,0 +1,43 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+COPS?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT^RFSTS?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT#CAINFO?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/ubloxinfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/ubloxinfo.gcom new file mode 100644 index 0000000..9ebe9dc --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/ubloxinfo.gcom @@ -0,0 +1,43 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+CESQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+URAT?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+UCGED?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/ussd.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/ussd.gcom new file mode 100644 index 0000000..254da89 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/ussd.gcom @@ -0,0 +1,29 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.05 + waitquiet 1 0.2 +:start +let f=20 +let $x=$env("ATCMD") +send $x+"^m" +waitfor 2 "OK" +let t=time()+f +let $s="" +gosub getresult +let x=len($s) +if x<2 let $s="^mUSSD TIMEOUT ERROR" +print $s +:continue +exit 0 +:getresult +get 1 "^m" $u +let x=len($u) +let $v=$s +if x>0 let $s=$v+$u +if $right(" "+$s,4) = '",15' return +if $right(" "+$s,4) = '",72' return +if $right(" "+$s,4) = '",68' return +if $mid($s,0,30)="^j+CME ERROR:" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/zteinfo.gcom b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/zteinfo.gcom new file mode 100644 index 0000000..013447c --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gcom/zteinfo.gcom @@ -0,0 +1,58 @@ +opengt + set com 115200n81 + set comecho off + set senddelay 0.02 + waitquiet 0.2 0.2 + +let $g=$env("TIMEOUT") +if $g = "" let f=25 +else let f = val($g) + +send "AT+CSQ^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+ZPAS?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+ZRSSI^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+ZRSSI?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+ZSINR^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+ZSNT?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + +send "AT+ZCELLINFO?^m" +let t=time()+f +gosub getresult +if $s="^mTIMEOUT ERROR" print $s + + exit 0 + +:getresult +get 1 "^m" $s +let x=len($s) +if x=0 let $s="^mTIMEOUT ERROR" +else print $s +if $s="^jOK" return +if $mid($s,0,6)="^jERROR" return +if $mid($s,0,8)="^jCOMMAND" return +if $mid($s,0,11)="^j+CME ERROR" return +if time()>t return +goto getresult diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gpio-set.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/gpio-set.sh new file mode 100644 index 0000000..9ec628e --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gpio-set.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +GPIO=$1 # name or number (without "gpio" prefix) +VAL=$2 # 0 or 1 +WAIT=$3 # delay in seconds, optional + +log() { + modlog "GPIO Set" "$@" +} + + +[ -n "$WAIT" ] && sleep $WAIT + +if `echo "$GPIO" | grep -q "^[0-9]*$"`; then + GPIO=gpio$GPIO +fi + +if [ -w /sys/class/gpio/$GPIO/value ]; then + echo "$VAL" > /sys/class/gpio/$GPIO/value + log "GPIO $GPIO has been set to $VAL" +else + log "GPIO $GPIO is not writable" +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/gpiomodel.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/gpiomodel.lua new file mode 100644 index 0000000..fe63096 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/gpiomodel.lua @@ -0,0 +1,221 @@ +#!/usr/bin/lua + +mfile = "/tmp/sysinfo/model" +echo = 1 +model = {} +gpio = {} +gpio2 = {} +gpio3 = {} +gpio4 = {} +gpioname = {} +gpioname2 = {} +gpioname3 = {} +gpioname4 = {} + +pin = nil +pin2 = nil + +model[1] = "10u" +gpio[1] = 18 +model[2] = "11u" +gpio[2] = 8 +model[3] = "13u" +gpio[3] = 18 +model[4] = "mr3020" +gpio[4] = 8 +model[5] = "3040" +gpio[5] = 18 +model[6] = "3220" +gpio[6] = 6 +model[7] = "3420" +gpio[7] = 6 +model[8] = "wdr3500" +gpio[8] = 12 +gpioname[8] = "tp-link:power:usb" +model[9] = "wdr3600" +gpio[9] = 22 +gpioname[9] = "tp-link:power:usb1" +gpio2[9] = 21 +gpioname2[9] = "tp-link:power:usb2" +model[10] = "wdr4300" +gpio[10] = 22 +gpioname[10] = "tp-link:power:usb1" +gpio2[10] = 21 +gpioname2[10] = "tp-link:power:usb2" +model[11] = "wdr4310" +gpio[11] = 22 +gpioname2[11] = "tp-link:power:usb2" +gpioname[11] = "tp-link:power:usb1" +gpio2[11] = 21 +model[12] = "wdr4900" +gpio[12] = 10 +model[13] = "703n" +gpio[13] = 8 +model[14] = "710n" +gpio[14] = 8 +model[15] = "720" +gpio[15] = 8 +model[16] = "842" +gpio[16] = 6 +gpioname[16] = "tp-link:power:usb" +model[17] = "1043" +gpio[17] = 21 +gpioname[17] = "tp-link:power:usb" +model[18] = "4530" +gpio[18] = 22 +model[19] = "archer" +gpio[19] = 22 +gpio2[19] = 21 +gpioname2[19] = "tp-link:power:usb2" +gpioname[19] = "tp-link:power:usb1" +model[20] = "ar150" +gpio[20] = 6 +model[21] = "domino" +gpio[21] = 6 +model[22] = "300a" +gpio[22] = 0 +model[23] = "mt300n" +gpio[23] = 0 +model[24] = "ar750s" +gpio[24] = 7 +model[25] = "oolite" +gpio[25] = 18 +model[26] = "7800" +gpio[26] = 15 +gpio2[26] = 16 +model[27] = "m11g" +gpio[27] = 9 +gpioname[27] = "gpio9" +model[28] = "m33g" +gpio[28] = 9 +gpio2[28] = 10 +gpio3[28] = 11 +gpio4[28] = 12 +gpioname[28] = "pcie0_power" +gpioname2[28] = "pcie1_power" +gpioname3[28] = "pcie2_power" +gpioname4[28] = "usb_power" +model[29] = "rbsxtr" +gpio[29] = 13 +model[30] = "ap147" +gpio[30] = 13 +model[31] = "gigamod" +gpio[31] = 16 +gpioname[31] = "power_usb" +model[32] = "turbomod" +gpio[32] = 17 +gpioname[32] = "power_usb" +model[33] = "mk01" +gpio[33] = 6 + +numodel = 33 + +local file = io.open(mfile, "r") +if file == nil then + return +end + +name = nil +name2 = nil +line = file:read("*line") +file:close() +line = line:lower() + +for i=1,numodel do + start, ends = line:find(model[i]) + if start ~= nil then + if model[i] == "3420" then + start, ends = line:find("v1") + if start ~= nil then + pin = gpio[i] + pin2 = nil + else + pin = 4 + pin2 = nil + end + elseif model[i] == "3220" then + start, ends = line:find("v1") + if start ~= nil then + pin = gpio[i] + pin2 = nil + else + pin = 8 + pin2 = nil + end + elseif model[i] == "1043" then + start, ends = line:find("v2") + if start ~= nil then + pin = gpio[i] + pin2 = nil + name = gpioname[i] + name2 = nil + end + elseif model[i] == "842" then + start, ends = line:find("v3") + if start == nil then + start, ends = line:find("v2") + if start == nil then + pin = gpio[i] + pin2 = gpio2[i] + name = gpioname[i] + name2 = gpioname2[i] + else + pin = 4 + pin2 = nil + name = gpioname[i] + name2 = nil + end + end + elseif model[i] == "archer" then + start, ends = line:find("c20") + if start == nil then + pin = gpio[i] + pin2 = gpio2[i] + name = gpioname[i] + name2 = gpioname2[i] + end + elseif model[i] == "mt300n" then + start, ends = line:find("v2") + if start ~= nil then + pin = 11 + pin2 = nil + name = "usb" + name2 = nil + else + pin = gpio[i] + pin2 = nil + name = gpioname[i] + name2 = nil + end + else + pin = gpio[i] + pin2 = gpio2[i] + name = gpioname[i] + name2 = gpioname2[i] + end + break + end +end + +if pin ~= nil then + local tfile = io.open("/tmp/gpiopin", "w") + if pin2 ~= nil then + tfile:write("GPIOPIN=\"", pin, "\"\n") + tfile:write("GPIOPIN2=\"", pin2, "\"") + else + tfile:write("GPIOPIN=\"", pin, "\"") + end + tfile:close() +end +if name ~= nil then + local tfile = io.open("/tmp/gpioname", "w") + if name2 ~= nil then + tfile:write("GPIONAME=\"", name, "\"\n") + tfile:write("GPIONAME2=\"", name2, "\"") + else + tfile:write("GPIONAME=\"", name, "\"") + end + tfile:close() +else + os.remove("/tmp/gpioname") +end diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/idown.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/idown.lua new file mode 100644 index 0000000..cda3061 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/idown.lua @@ -0,0 +1,22 @@ +#!/usr/bin/lua + +cmd = arg[1] +interface = arg[2] + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +if interface ~= "wan" and interface ~= "wwan" then + s, e = interface:find("wan") + if s ~= nil then + mnum = trim(interface:sub(e+1)) + if cmd == "1" then + os.execute("/usr/lib/rooter/connect/disablemw3.sh " .. mnum) + line = "echo \"0\" > /tmp/mdown" .. mnum + else + line = "rm -f /tmp/mdown" .. mnum + end + os.execute(line) + end +end \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/initialize.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/initialize.sh new file mode 100644 index 0000000..194a78c --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/initialize.sh @@ -0,0 +1,295 @@ +#!/bin/sh +. /lib/functions.sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +CODENAME="ROOter " +if [ -f "/etc/codename" ]; then + source /etc/codename +fi + +# +# Set the maximum number of modems supported +# +MAX_MODEMS=2 +MODCNT=$MAX_MODEMS + +log() { + modlog "ROOter Initialize" "$@" +} + +do_zone() { + local config=$1 + local name + local network + + config_get name $1 name + config_get network $1 network + newnet=$network + if [ $name = wan ]; then + WAN1=$(echo $network | grep "wan1") + if [ -z $WAN1 ]; then + COUNTER=1 + while [ $COUNTER -le $MODCNT ]; do + newnet="$newnet wan$COUNTER" + let COUNTER=COUNTER+1 + done + uci_set firewall "$config" network "$newnet" + uci_commit firewall + /etc/init.d/firewall restart + fi + fi +} + +firstboot() { + HO=$(uci get system.@system[-1].hostname) + if [ $HO = "OpenWrt" ]; then + uci set system.@system[-1].hostname="OpenWrt" + echo "OpenWrt" > /proc/sys/kernel/hostname + fi + if [ $HO = "LEDE" ]; then + uci set system.@system[-1].hostname="LEDE" + echo "LEDE" > /proc/sys/kernel/hostname + fi + uci set system.@system[-1].cronloglevel="9" + uci commit system + + AP=$(uci -q get profile.default.apn) + if [ -z "$AP" ]; then + uci set profile.default.apn="internet" + uci commit profile + fi + + log "ROOter First Boot finalized" + + config_load firewall + config_foreach do_zone zone + + source /etc/openwrt_release + if [ $DISTRIB_RELEASE = "SNAPSHOT" ]; then + DISTRIB_RELEASE="21.02.2" + fi + tone=$(echo "$DISTRIB_RELEASE" | grep "21.02") +} + +if [ -e /tmp/installing ]; then + exit 0 +fi + + +log " Initializing Rooter" + +sed -i -e 's|/etc/savevar|#removed line|g' /etc/rc.local + +[ -f "/etc/firstboot" ] || { + firstboot +} + +mkdir -p $ROOTER_LINK + +uci delete modem.Version +uci set modem.Version=version +uci set modem.Version.ver=$CODENAME +uci commit modem + +source /etc/openwrt_release +rm -f /etc/openwrt_release +if [ $DISTRIB_RELEASE = "SNAPSHOT" ]; then + DISTRIB_RELEASE="21.02.2" +fi +if [ -e /etc/custom ]; then + lua $ROOTER/customname.lua + DISTRIB_DESCRIPTION=$(uci get modem.Version.ver) + DISTRIB_REVISION=" " +else + DISTRIB_DESCRIPTION=$(uci get modem.Version.ver)" ( "$DISTRIB_ID" "$DISTRIB_RELEASE" )" + DISTRIB_REVISION=" " +fi +echo "$(uci get modem.Version.ver)" > /etc/revision +echo 'DISTRIB_ID="'"$DISTRIB_ID"'"' >> /etc/openwrt_release +echo 'DISTRIB_RELEASE="'"$DISTRIB_RELEASE"'"' >> /etc/openwrt_release +echo 'DISTRIB_REVISION="'"$DISTRIB_REVISION"'"' >> /etc/openwrt_release +echo 'DISTRIB_CODENAME="'"$DISTRIB_CODENAME"'"' >> /etc/openwrt_release +echo 'DISTRIB_TARGET="'"$DISTRIB_TARGET"'"' >> /etc/openwrt_release +echo 'DISTRIB_DESCRIPTION="'"$DISTRIB_DESCRIPTION"'"' >> /etc/openwrt_release + +MODSTART=1 +WWAN=0 +USBN=0 +ETHN=1 +BASEPORT=0 +WDMN=0 +if + ifconfig eth1 &>/dev/null +then + if [ -e "/sys/class/net/eth1/device/bInterfaceProtocol" ]; then + ETHN=1 + else + ETHN=2 + fi +fi + +echo 'MODSTART="'"$MODSTART"'"' > /tmp/variable.file +echo 'WWAN="'"$WWAN"'"' >> /tmp/variable.file +echo 'USBN="'"$USBN"'"' >> /tmp/variable.file +echo 'ETHN="'"$ETHN"'"' >> /tmp/variable.file +echo 'WDMN="'"$WDMN"'"' >> /tmp/variable.file +echo 'BASEPORT="'"$BASEPORT"'"' >> /tmp/variable.file + +echo 'MODCNTX="'"$MODCNT"'"' > /tmp/modcnt +uci set modem.general.max=$MODCNT +uci set modem.general.modemnum=1 +uci set modem.general.smsnum=1 +uci set modem.general.miscnum=1 + +OPING=$(uci -q get modem.ping.alive) +if [ ! -z $OPING ]; then + uci delete modem.ping +fi + +ifname1="ifname" +if [ -n "$tone" -o -e /etc/newstyle ]; then + ifname1="device" +fi + +COUNTER=1 +while [ $COUNTER -le $MODCNT ]; do + uci delete modem.modem$COUNTER + uci set modem.modem$COUNTER=modem + uci set modem.modem$COUNTER.empty=1 + + IPEX=$(uci get modem.pinginfo$COUNTER.alive) + if [ -z $IPEX ]; then + uci set modem.pinginfo$COUNTER=pinfo$COUNTER + uci set modem.pinginfo$COUNTER.alive="0" + fi + + INEX=$(uci get modem.modeminfo$COUNTER) + if [ -z $INEX ]; then + uci set modem.modeminfo$COUNTER=minfo$COUNTER + fi + + rm -f $ROOTER_LINK/getsignal$COUNTER + rm -f $ROOTER_LINK/reconnect$COUNTER + rm -f $ROOTER_LINK/create_proto$COUNTER + $ROOTER/signal/status.sh $COUNTER "No Modem Present" + + uci -q delete network.wan$COUNTER + uci set network.wan$COUNTER=interface + uci set network.wan$COUNTER.proto=dhcp + uci set network.wan$COUNTER.metric=$COUNTER"0" + uci set network.wan$COUNTER.${ifname1}="wan"$COUNTER + + if [ -e /etc/config/mwan3 ]; then + ENB=$(uci -q get mwan3.wan$COUNTER.enabled) + if [ ! -z $ENB ]; then + uci set mwan3.wan$COUNTER.enabled=0 + fi + fi + + if [ -e /etc/config/failover ]; then + uci delete failover.Modem$COUNTER + uci set failover.Modem$COUNTER=member + fi + + let COUNTER=COUNTER+1 +done + +if [ -e /etc/config/failover ]; then + uci delete failover.Wan + EXX=$(uci get network.wan) + if [ ! -z $EXX ]; then + uci set failover.Wan=member + fi + uci delete failover.Hotspot + uci set failover.Hotspot=member + uci commit failover + ENB=$(uci get failover.enabled.enabled) + if [ $ENB = "1" ]; then + if [ -e $ROOTER/connect/failover.sh ]; then + log "Starting Failover System" + $ROOTER/connect/failover.sh & + fi + fi +fi + +PRO=$(uci -q get network.wan.proto) +if [ ! -z $PRO ]; then + uci set network.wan.metric="1" +fi + +SM=$(uci get modem.sms) +if [ -z $SM ]; then + uci set modem.sms="sms" + uci set modem.sms.menable="0" + uci set modem.sms.slots="0" +fi + +uci commit modem +uci commit network +if [ -e /etc/config/mwan3 ]; then + uci commit mwan3 +fi + +if [ -e $ROOTER/removeipv6.sh ]; then + $ROOTER/removeipv6.sh +fi + +if [ -e /etc/hotplug.d/10-motion ]; then + rm -f /etc/hotplug.d/10-motion +fi +if [ -e /etc/hotplug.d/20-mjpg-streamer ]; then + rm -f /etc/hotplug.d/20-mjpg-streamer +fi +if [ -e /etc/hotplug.d/50-printer ]; then + rm -f /etc/hotplug.d/50-printer +fi +if [ -e $ROOTER/special.sh ]; then + $ROOTER/special.sh +fi + +lua $ROOTER/gpiomodel.lua + +HO=$(uci get system.@system[-1].hostname) +if [ $HO = "OpenWrt" ]; then + uci set system.@system[-1].hostname="OpenWrt" + uci commit system +fi + +if [ -e /usr/lib/lua/luci/model/cbi/admin_system/cronnew.lua ]; then + mv -f /usr/lib/lua/luci/model/cbi/admin_system/cronnew.lua /usr/lib/lua/luci/model/cbi/admin_system/crontab.lua +fi + + +if [ -f "/etc/firstboot" ]; then + echo 'FIRSTBOOT="'"1"'"' > /etc/firstboot +else + echo 'FIRSTBOOT="'"0"'"' > /etc/firstboot + echo 'BOOTTIME="'"$(date +%s)"'"' > /tmp/boottime +fi + +# +# Added modems to various drivers +# +#source /etc/flash +#if [ "$FLASH" = "4" ]; then +#fi +#echo "413c 81b6" > /sys/bus/usb-serial/drivers/option1/new_id +echo "1546 1146" > /sys/bus/usb-serial/drivers/option1/new_id +echo "106c 3718" > /sys/bus/usb-serial/drivers/option1/new_id +#echo "1199 9091" > /sys/bus/usb-serial/drivers/option1/new_id + +# end of bootup +echo "0" > /tmp/bootend.file + +/etc/init.d/dnsmasq restart + +chown -R root:root /etc/dropbear/ +chmod 700 /etc/dropbear/ +chmod 644 /etc/dropbear/authorized_keys 2>/dev/null + +if [ ! -z $tone ]; then + [ -e /etc/newstyle ] || touch /etc/newstyle + #reboot -f +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/log/at-logger b/rooter/ext-rooter-basic/files/usr/lib/rooter/log/at-logger new file mode 100644 index 0000000..ca7d6e6 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/log/at-logger @@ -0,0 +1,12 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +TEXT=$1 +DATE=$(date +%c) + +echo " " >> /tmp/atlog +echo "$DATE : $TEXT" >> /tmp/atlog +lua $ROOTER/log/rotate.lua /tmp/atlog /tmp/attlog +mv /tmp/attlog /tmp/atlog + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/log/logger b/rooter/ext-rooter-basic/files/usr/lib/rooter/log/logger new file mode 100644 index 0000000..e78b574 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/log/logger @@ -0,0 +1,17 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +TEXT=$1 +DATE=$(date +%c) + +wc -l $ROOTER/log/connect.log > /tmp/linecnt +read lcnt fle < /tmp/linecnt +rm -f /tmp/linecnt +if [ $lcnt -ge 20 ]; then + start=$((lcnt-1)) + tail +$start $ROOTER/log/connect.log > /tmp/connect.log + mv /tmp/connect.log $ROOTER/log/connect.log +fi + +echo "$DATE : $TEXT" >> $ROOTER/log/connect.log diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/log/modlogger.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/log/modlogger.sh new file mode 100644 index 0000000..fde69f7 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/log/modlogger.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +TEXT=$1 +DATE=$(date +%c) + +modlog="/tmp/modlog.log" +tmplog="/tmp/tmodlog" + +echo "$DATE : $TEXT" >> $modlog +lua $ROOTER/log/mrotate.lua $modlog $tmplog +mv $tmplog $modlog + +exit 0 + +wc -l $modlog > /tmp/linecnt +read lcnt fle < /tmp/linecnt +rm -f /tmp/linecnt +if [ $lcnt -ge 200 ]; then + start=$((lcnt-1)) + tail +$start modlog > $tmplog + mv $tmplog $modlog +fi + +echo "$DATE : $TEXT" >> $modlog diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/log/mrotate.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/log/mrotate.lua new file mode 100644 index 0000000..0a5317d --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/log/mrotate.lua @@ -0,0 +1,39 @@ +#!/usr/bin/lua + +local uci = require "luci.model.uci".cursor() + +logfile = {} +infile = arg[1] +outfile = arg[2] + +i=0 +ifile = io.open(infile, "r") +if ifile == nil then + return +end +repeat + local line = ifile:read("*line") + if line == nil then + break + end + if string.len(line) > 1 then + i = i + 1 + logfile[i] = line + end +until 1==0 +ifile:close() + +maxs = 195 + +if i < maxs then + j = 1 +else + j = i - maxs - 1 +end +ofile = io.open(outfile, "w") +for k=j,i do + if logfile[k] ~= nil then + ofile:write(logfile[k] .. "\n") + end +end +ofile:close() \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/log/rotate.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/log/rotate.lua new file mode 100644 index 0000000..f866446 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/log/rotate.lua @@ -0,0 +1,43 @@ +#!/usr/bin/lua + +local uci = require "luci.model.uci".cursor() + +logfile = {} +infile = arg[1] +outfile = arg[2] + +i=0 +ifile = io.open(infile, "r") +if ifile == nil then + return +end +repeat + local line = ifile:read("*line") + if line == nil then + break + end + if string.len(line) > 1 then + i = i + 1 + logfile[i] = line + end +until 1==0 +ifile:close() + +bff = uci:get("variable", "info", "buffersize") +if bff == nil then + maxs = 50 +else + maxs = tonumber(bff) +end +if i < maxs then + j = 1 +else + j = i - maxs - 1 +end +ofile = io.open(outfile, "w") +for k=j,i do + if logfile[k] ~= nil then + ofile:write(logfile[k] .. "\n") + end +end +ofile:close() \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/logprint.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/logprint.sh new file mode 100644 index 0000000..779337f --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/logprint.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# + +modlog "Log Print " "$1 $2 $3 $4 $5 $6" +exit 0 diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/atcmd.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/atcmd.sh new file mode 100644 index 0000000..efda95d --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/atcmd.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ATCMDD=$1 + +CURRMODEM=$(uci get modem.general.miscnum) +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) + +M2=$(echo "$ATCMDD" | sed -e "s#~#\"#g") +COPS="+cops=?" +QOPS="+qops?" +M3=$(echo "$M2" | awk '{print tolower($0)}') +if `echo ${M3} | grep "${COPS}" 1>/dev/null 2>&1`; then + export TIMEOUT="120" +elif `echo ${M3} | grep "${QOPS}" 1>/dev/null 2>&1`; then + export TIMEOUT="120" +else + export TIMEOUT="5" +fi +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M2") +echo "$OX" > /tmp/result$CURRMODEM.at diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/celltype.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/celltype.sh new file mode 100644 index 0000000..d1b3fb1 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/celltype.sh @@ -0,0 +1,495 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + modlog "Cell type $CURRMODEM" "$@" +} + +zte_type() { + ATCMDD="AT+ZSNT?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$($ROOTER/common/processat.sh "$OX") + ZSNT=$(echo "$OX" | awk -F[,\ ] '/^\+ZSNT:/ {print $2}') + if [ "x$ZSNT" != "x" ]; then + NETMODE="-" + if [ $ZSNT = "0" ]; then + ZSNTX=$(echo "$OX" | awk -F[,\ ] '/^\+ZSNT:/ {print $4}') + case $ZSNTX in + "0" ) + NETMODE="1" + ;; + "1" ) + NETMODE="2" + ;; + "2" ) + NETMODE="4" + ;; + "6" ) + NETMODE="6" + ;; + esac + else + case $ZSNT in + "1" ) + NETMODE="3" + ;; + "2" ) + NETMODE="5" + ;; + "6" ) + NETMODE="7" + ;; + esac + fi + fi + uci set modem.modem$CURRMODEM.modemtype="1" + uci set modem.modem$CURRMODEM.netmode=$NETMODE + uci commit modem +} + +sierra_type() { + ATCMDD="AT!SELRAT?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + SELRAT=$(echo $OX | grep -o "!SELRAT:[^0-9]\+[0-9]\{2\}" | grep -o "[0-9]\{2\}") + if [ -n "$SELRAT" ]; then + case $SELRAT in + "01" ) + NETMODE="5" + ;; + "02" ) + NETMODE="3" + ;; + "06" ) + NETMODE="7" + ;; + * ) + NETMODE="1" + ;; + esac + fi + uci set modem.modem$CURRMODEM.modemtype="2" + uci set modem.modem$CURRMODEM.netmode=$NETMODE + uci commit modem +} + +huawei_type() { + ATCMDD="AT^SYSCFGEX?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$($ROOTER/common/processat.sh "$OX") + SYSCFG=$(echo "$OX" | awk -F[,\"] '/^\^SYSCFGEX:/ {print $2}') + if [ "x$SYSCFG" != "x" ]; then + NETMODE="-" + case $SYSCFG in + "00" ) + NETMODE="1" + ;; + "01" ) + NETMODE="3" + ;; + "02" ) + NETMODE="5" + ;; + "03" ) + NETMODE="7" + ;; + * ) + ACQ=${SYSCFG:0:2} + case $ACQ in + "01" ) + NETMODE="2" + ;; + "02" ) + NETMODE="4" + ;; + "03" ) + NETMODE="6" + ;; + esac + ;; + esac + uci set modem.modem$CURRMODEM.modemtype="3" + else + ATCMDD="AT^SYSCFG?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + OX=$($ROOTER/common/processat.sh "$OX") + SYSCFG=$(echo "$OX" | awk -F[,\ ] '/^\^SYSCFG:/ {print $2}') + if [ "x$SYSCFG" != "x" ]; then + NETMODE="-" + case $SYSCFG in + "7" ) + NETMODE="1" + ;; + "13" ) + NETMODE="3" + ;; + "14" ) + NETMODE="5" + ;; + * ) + SYSCFG=$(echo "$OX" | awk -F[,\ ] '/^\^SYSCFG:/ {print $3}') + case $SYSCFG in + "0" ) + NETMODE="1" + ;; + "1" ) + NETMODE="2" + ;; + "2" ) + NETMODE="4" + ;; + esac + ;; + esac + uci set modem.modem$CURRMODEM.modemtype="4" + fi + fi + uci set modem.modem$CURRMODEM.netmode=$NETMODE + uci commit modem +} + +ublox_type() { + ATCMDD="AT+URAT?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + URAT=$(echo $OX" " | grep -o "+URAT: .\+ OK " | tr " " ",") + URAT1=$(echo $URAT | cut -d, -f2) + URAT2=$(echo $URAT | cut -d, -f3) + if [ -n "$URAT1" ]; then + NETMODE="-" + case $URAT1 in + "0" ) + NETMODE="3" + ;; + "2" ) + NETMODE="5" + ;; + "3" ) + NETMODE="7" + ;; + * ) + case $URAT2 in + "0" ) + NETMODE="2" + ;; + "2" ) + NETMODE="4" + ;; + "3" ) + NETMODE="1" + ;; + esac + ;; + esac + uci set modem.modem$CURRMODEM.modemtype="5" + fi + uci set modem.modem$CURRMODEM.netmode=$NETMODE + uci commit modem +} + +quectel_type() { + idVidP=$idV":"$idP + ATCMDD="AT+CGMM" + model=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + EM20=$(echo "$model" | grep "EM20") + if [ $EM20 ]; then + idVidP=$idV":"$idP"0" + fi + if [ "$idVidP" == "2c7c:0800" -o "$idVidP" == "2c7c:0620" -o "$idVidP" == "2c7c:030b" -o "$idVidP" == "2c7c:0801" -o "$idVidP" == "2c7c:0900" ]; then + ATCMDD="AT+QNWPREFCFG=\"mode_pref\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + QNSM=$(echo $OX | grep -o ",[AUTOLENR5GWCDM:]\+" | tr ',' ' ') + QNSM=$(echo $QNSM) + if [ -n "$QNSM" ]; then + case $QNSM in + "AUTO" ) + NETMODE="1" + ;; + "LTE" ) + NETMODE="7" + ;; + "LTE:NR5G" ) + NETMODE="8" + ;; + "NR5G" ) + NETMODE="9" + ;; + "WCDMA" ) + NETMODE="5" + ;; + esac + uci set modem.modem$CURRMODEM.modemtype="6" + fi + else + ATCMDD="AT+QCFG=\"nwscanmode\"" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + QNSM=$(echo $OX | grep -o "+QCFG: \"nwscanmode\",[0-9]" | grep -o "[0-9]") + if [ -n "$QNSM" ]; then + case $QNSM in + "0" ) + NETMODE="1" + ;; + "1" ) + NETMODE="3" + ;; + "2"|"5" ) + NETMODE="5" + ;; + "3" ) + NETMODE="7" + ;; + esac + uci set modem.modem$CURRMODEM.modemtype="6" + fi + fi + uci set modem.modem$CURRMODEM.netmode=$NETMODE + uci commit modem +} + +meig_type() { + if [ $idV == "2dee" ]; then + ATCMDD="AT^SYSCFGEX?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + RATs=$(echo "$OX" | grep -o "\^SYSCFGEX: \"[0-9]\{2,6\}\"" | grep -o "[0-9]\{2,6\}") + if [ -n "$RATs" ]; then + case $RATs in + "02" ) + NETMODE="5" ;; + "03" ) + NETMODE="7" ;; + "04" ) + NETMODE="9" ;; + "0203" | "0204" | "020304" | "020403" ) + NETMODE="4" ;; + "0304" | "0302" | "030402" | "030204" ) + NETMODE="6" ;; + "0403" ) + NETMODE="8" ;; + * ) + NETMODE="1" ;; + esac + fi + else + ATCMDD="AT+MODODR?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + MODODR=$(echo $OX | grep -o "[0-9]") + if [ -n "$MODODR" ]; then + case $MODODR in + "1"|"8" ) + NETMODE="5" ;; + "2" ) + NETMODE="1" ;; + "3" ) + NETMODE="3" ;; + "5" ) + NETMODE="7" ;; + esac + fi + fi + uci set modem.modem$CURRMODEM.modemtype="7" + uci set modem.modem$CURRMODEM.netmode=$NETMODE + uci commit modem +} + +telit_type() { + ATCMDD="AT^SYSCONFIG?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + SCFG=$(echo $OX | grep -o "\^SYSCONFIG: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") + if [ -n "$SCFG" ]; then + PREF=$(echo $OX | grep -o "\^SYSCONFIG: 2,[0-9]" | grep -o ",[0-9]") + case $SCFG in + "13" ) + NETMODE="3" ;; + "14" ) + NETMODE="5" ;; + "17" ) + NETMODE="7" ;; + * ) + NETMODE="1" ;; + esac + uci set modem.modem$CURRMODEM.modemtype="8" + fi + uci set modem.modem$CURRMODEM.netmode=$NETMODE + uci commit modem +} + +fibocom_type() { + NETMODE="" + idPP=${idP:1:1} + if [ "$idPP" = "1" ]; then + ATCMDD="AT+GTRAT?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + MRAT=$(echo $OX | grep -o "+GTRAT: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}") + if [ -n "$MRAT" ]; then + case $MRAT in + "2" ) + NETMODE="5" ;; + "3" ) + NETMODE="7" ;; + "14" ) + NETMODE="9" ;; + "17" ) + NETMODE="8" ;; + * ) + NETMODE="1" ;; + esac + fi + else + ATCMDD="AT+XACT?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + XACT=$(echo $OX | grep -o "+XACT: [0-9]" | grep -o "[0-9]") + if [ -n "$XACT" ]; then + PREF=$(echo $OX | grep -o "+XACT: [0-9],[0-9]" | grep -o ",[0-9]") + case $XACT in + "1" ) + NETMODE="5" ;; + "2" ) + NETMODE="7" ;; + "4" ) + if [ "$PREF" = ",1" ]; then + NETMODE="4" + else + NETMODE="6" + fi ;; + * ) + NETMODE="6" ;; + esac + + fi + fi + uci set modem.modem$CURRMODEM.modemtype="9" + uci set modem.modem$CURRMODEM.netmode=$NETMODE + uci commit modem +} + +simcom_type() { + ATCMDD="AT+CNMP?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + CNMP=$(echo "$OX" | grep -o "+CNMP:[ ]*[0-9]\{1,3\}" | grep -o "[0-9]\{1,3\}") + if [ -n "$CNMP" ]; then + case $CNMP in + "2"|"55" ) + NETMODE="1" ;; + "13" ) + NETMODE="3" ;; + "14" ) + NETMODE="5" ;; + "38" ) + NETMODE="7" ;; + "71" ) + NETMODE="9" ;; + "109" ) + NETMODE="8" ;; + * ) + NETMODE="0" ;; + esac + fi + uci set modem.modem$CURRMODEM.modemtype="10" + uci set modem.modem$CURRMODEM.netmode=$NETMODE + uci commit modem +} + +quanta_type() { + ATCMDD="AT^QCNCFG?" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + TECH=$(echo $OX | grep -o "\^QCNCFG: \"[0123]\{2\}\"" | grep -o "[0123]\{2\}") + case $TECH in + "02") + NETMODE="5" + ;; + "03") + NETMODE="7" + ;; + *) + NETMODE="1" + ;; + esac + uci set modem.modem$CURRMODEM.modemtype="11" + uci set modem.modem$CURRMODEM.netmode=$NETMODE + uci commit modem +} + +CURRMODEM=$1 +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) + +idV=$(uci get modem.modem$CURRMODEM.idV) +idP=$(uci -q get modem.modem$CURRMODEM.idP) +NETMODE="-" + +# This case statement should be kept in sync with: $ROOTER/signal/modemsignal.sh +case $idV in +"1199"|"0f3d" ) + sierra_type + ;; +"19d2" ) + if [ $idP = 1432 ]; then + telit_type + else + zte_type + fi + ;; +"12d1" ) + huawei_type + ;; +"2c7c" ) + quectel_type + ;; +"2cb7"|"1508"|"8087" ) + fibocom_type + ;; +"2dee" ) + meig_type + ;; +"05c6" ) + case $idP in + "f601" ) + meig_type + ;; + "5042" ) + telit_type + ;; + "9090"|"9003"|"9215" ) + quectel_type + ;; + "90db" ) + simcom_type + ;; + * ) + : + ;; + esac + ;; +"1bc7" ) + telit_type + ;; +"1410" ) + : + ;; +"413c" ) + case $idP in + "81d7"|"81d8" ) + telit_type + ;; + * ) + sierra_type + ;; + esac + ;; +"0489" |"03f0" ) + telit_type + ;; +"1e0e" ) + simcom_type + ;; +"8087" ) + if [ $idP = "095a" ]; then + fibocom_type + fi + ;; +"0408" ) + quanta_type + ;; +* ) + : + ;; +esac +exit diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em060-2xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em060-2xbands new file mode 100644 index 0000000..aa600ca --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em060-2xbands @@ -0,0 +1,29 @@ +2 2 +2 5 +2 12 +2 13 +2 39 +4 4 +4 5 +4 12 +4 13 +4 29 +5 5 +5 7 +5 25 +5 30 +5 66 +7 7 +7 12 +7 26 +12 12 +12 25 +12 30 +12 66 +13 66 +25 25 +25 26 +30 29 +66 29 +66 66 +41 41 diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em12-2xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em12-2xbands new file mode 100644 index 0000000..307919e --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em12-2xbands @@ -0,0 +1,46 @@ +1 3 +1 5 +1 18 +1 19 +1 20 +1 26 +2 2 +2 4 +2 5 +2 12 +2 13 +2 17 +2 29 +2 30 +2 66 +3 3 +3 5 +2 7 +3 8 +3 19 +3 20 +3 28 +4 4 +4 5 +4 12 +4 13 +4 17 +4 19 +4 30 +5 7 +5 30 +5 66 +7 7 +7 20 +7 28 +12 30 +13 66 +19 21 +20 32 +29 30 +38 38 +39 39 +39 41 +40 40 +41 41 +66 66 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em12-3xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em12-3xbands new file mode 100644 index 0000000..43f7600 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em12-3xbands @@ -0,0 +1,43 @@ +1 3 5 +1 3 7 +1 3 8 +1 3 19 +1 3 20 +1 3 28 +1 7 20 +2 4 5 +2 4 13 +2 5 30 +2 12 30 +2 29 30 +3 7 20 +3 7 28 +3 7 8 +4 5 30 +4 12 30 +4 29 30 +5 66 2 +13 66 2 +66 12 30 +66 29 30 +66 5 30 +2 14 66 +2 2 5 +2 2 13 +3 3 7 +3 7 7 +3 3 20 +3 3 28 +3 3 1 +4 4 5 +4 4 13 +7 7 28 +5 66 66 +13 66 66 +66 66 2 +14 66 66 +39 39 41 +39 41 41 +40 40 40 +41 41 41 +66 66 66 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-2xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-2xbands new file mode 100644 index 0000000..74a2677 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-2xbands @@ -0,0 +1,50 @@ +1 3 +1 5 +1 18 +1 19 +1 20 +1 26 +2 2 +2 4 +2 5 +2 12 +2 13 +2 14 +2 17 +2 29 +2 30 +2 66 +3 3 +3 5 +2 7 +3 8 +3 19 +3 20 +3 28 +4 4 +4 5 +4 12 +4 13 +4 17 +4 19 +4 30 +5 7 +5 30 +5 66 +7 7 +7 20 +7 28 +12 30 +13 66 +14 30 +14 66 +29 30 +38 38 +39 39 +39 41 +40 40 +41 41 +66 5 +66 12 +66 29 +66 30 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-3xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-3xbands new file mode 100644 index 0000000..701af64 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-3xbands @@ -0,0 +1,41 @@ +1 3 5 +1 3 7 +1 3 19 +1 3 20 +1 3 28 +1 7 20 +2 4 5 +2 4 13 +2 5 30 +2 12 30 +2 29 30 +3 7 20 +3 7 28 +3 7 8 +4 5 30 +4 12 30 +4 29 30 +5 66 2 +13 66 2 +66 12 30 +66 29 30 +66 5 30 +2 14 66 +2 2 5 +2 2 13 +3 3 7 +3 7 7 +3 3 20 +3 3 28 +4 4 5 +4 4 13 +7 7 28 +5 66 66 +13 66 66 +39 39 41 +39 41 41 +40 40 40 +41 41 41 +66 66 2 +14 66 66 +66 66 66 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-4xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-4xbands new file mode 100644 index 0000000..5489ad5 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em20-4xbands @@ -0,0 +1,8 @@ +1 1 3 28 0 +1 3 40 40 0 +1 3 7 7 0 +1 3 3 7 7 +1 3 3 40 40 +1 3 7 7 28 +2 13 66 66 0 +3 3 7 7 28 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7411-2xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7411-2xbands new file mode 100644 index 0000000..4667685 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7411-2xbands @@ -0,0 +1,29 @@ +2 2 +2 5 +2 7 +2 12 +2 13 +2 14 +2 71 +4 4 +4 5 +4 7 +4 12 +4 13 +4 71 +5 5 +5 66 +7 7 +7 12 +12 66 +13 66 +14 66 +25 25 +25 26 +26 41 +41 41 +42 42 +43 43 +48 48 +66 66 +66 71 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7411-3xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7411-3xbands new file mode 100644 index 0000000..a50f0f9 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7411-3xbands @@ -0,0 +1,8 @@ +2 2 2 +7 7 7 +12 12 12 +41 41 41 +42 42 42 +43 43 43 +48 48 48 +66 66 66 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7511-2xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7511-2xbands new file mode 100644 index 0000000..ea770ac --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7511-2xbands @@ -0,0 +1,60 @@ +1 3 +1 5 +1 7 +1 8 +1 18 +1 19 +1 20 +1 26 +1 41 +1 42 +2 2 +2 4 +2 5 +2 12 +2 13 +2 28 +2 29 +2 30 +2 46 +2 66 +3 3 +3 5 +3 7 +3 8 +3 19 +3 20 +3 28 +3 41 +3 42 +4 4 +4 5 +4 7 +4 12 +4 13 +4 28 +4 29 +4 30 +4 46 +5 5 +5 7 +5 30 +5 46 +5 66 +7 7 +7 20 +7 28 +12 30 +12 66 +13 46 +13 66 +19 42 +20 32 +28 42 +29 30 +29 66 +30 66 +41 41 +41 42 +42 42 +48 48 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7511-3xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7511-3xbands new file mode 100644 index 0000000..f64b670 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7511-3xbands @@ -0,0 +1,55 @@ +1 3 5 +1 3 7 +1 3 8 +1 3 19 +1 3 20 +1 3 28 +1 5 7 +1 7 20 +1 7 7 +1 42 42 +2 2 5 +2 2 12 +2 2 13 +2 4 5 +2 4 7 +2 4 12 +2 4 13 +2 4 29 +2 5 30 +2 5 66 +2 7 7 +2 7 12 +2 12 30 +2 13 66 +2 29 30 +2 66 66 +3 3 5 +3 3 7 +3 7 7 +3 7 20 +3 7 28 +3 41 42 +3 41 41 +3 42 42 +4 4 5 +4 4 12 +4 4 13 +4 4 30 +4 5 30 +4 7 7 +4 7 12 +4 12 30 +4 29 30 +5 30 66 +5 66 66 +7 7 28 +12 30 66 +13 66 66 +19 42 42 +29 30 66 +41 42 42 +41 41 42 +41 41 41 +48 48 48 +66 66 66 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7565-2xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7565-2xbands new file mode 100644 index 0000000..3ff2f85 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7565-2xbands @@ -0,0 +1,14 @@ +1 18 +1 26 +1 41 +2 2 +2 28 +2 46 +4 28 +4 46 +5 5 +5 46 +20 32 +41 41 +42 42 +48 48 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7565-3xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7565-3xbands new file mode 100644 index 0000000..61b39c8 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/em7565-3xbands @@ -0,0 +1,51 @@ +1 3 5 +1 3 7 +1 3 8 +1 3 19 +1 3 20 +1 3 28 +1 42 42 +2 2 5 +2 2 12 +2 2 13 +2 4 5 +2 4 7 +2 4 12 +2 4 13 +2 4 29 +2 5 30 +2 5 66 +2 7 7 +2 7 12 +2 12 30 +2 13 66 +2 29 30 +2 66 66 +3 3 5 +3 3 7 +3 3 20 +3 3 28 +3 7 7 +3 7 20 +3 7 28 +3 41 42 +3 41 41 +3 42 42 +4 4 5 +4 4 12 +4 4 13 +4 4 30 +4 7 7 +4 7 12 +4 12 30 +4 29 30 +5 30 66 +5 66 66 +7 7 28 +12 30 66 +13 66 66 +29 30 66 +41 42 41 +41 41 42 +48 48 48 +66 66 66 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/ep06a-bands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/ep06a-bands new file mode 100644 index 0000000..e9565cd --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/ep06a-bands @@ -0,0 +1,27 @@ +2 2 +5 5 +2 12 +2 13 +2 29 +4 4 +4 5 +4 12 +4 13 +4 29 +7 5 +7 7 +7 12 +7 26 +25 5 +25 12 +25 25 +25 26 +30 5 +30 12 +30 29 +41 41 +66 5 +66 12 +66 13 +66 29 +66 66 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/ep06e-bands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/ep06e-bands new file mode 100644 index 0000000..0937585 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/ep06e-bands @@ -0,0 +1,32 @@ +1 5 +1 8 +1 20 +1 28 +1 1 +3 5 +3 7 +3 8 +3 20 +3 28 +3 3 +5 38 +5 40 +5 41 +7 5 +7 8 +7 20 +7 28 +7 7 +8 38 +8 40 +8 41 +20 32 +20 38 +20 40 +20 41 +28 38 +28 40 +28 41 +38 38 +40 40 +41 41 diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/l850-2xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/l850-2xbands new file mode 100644 index 0000000..540bd0a --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/l850-2xbands @@ -0,0 +1,35 @@ +1 3 +1 5 +1 18 +1 19 +1 20 +1 21 +1 26 +2 4 +2 5 +2 12 +2 13 +2 17 +2 29 +2 30 +2 66 +3 5 +3 7 +3 8 +3 19 +3 20 +3 28 +4 5 +4 12 +4 13 +4 17 +4 29 +4 30 +5 7 +5 30 +5 66 +7 20 +7 28 +12 30 +13 66 +29 30 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/l850-3xbands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/l850-3xbands new file mode 100644 index 0000000..29632c3 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/l850-3xbands @@ -0,0 +1,27 @@ +1 3 7 +1 3 19 +1 3 20 +1 19 21 +2 4 5 +2 4 13 +2 5 30 +2 12 30 +2 29 30 +3 7 20 +3 7 28 +4 5 30 +4 12 30 +4 29 30 +5 66 2 +13 66 2 +2 2 5 +2 2 13 +3 3 7 +3 7 7 +3 3 20 +4 4 5 +4 4 13 +5 66 66 +13 66 66 +66 66 2 +66 66 66 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/lock.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/lock.sh new file mode 100644 index 0000000..f9d8ff5 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/lock.sh @@ -0,0 +1,394 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "Lock Band $CURRMODEM" "$@" +} + +RESTART="1" + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + +fibdecode() { + j=$1 + tdec=$2 + mod=$3 + length=${#j} + jx=$j + length=${#jx} + + str="" + i=$((length-1)) + while [ $i -ge 0 ] + do + dgt="0x"${jx:$i:1} + DecNum=`printf "%d" $dgt` + Binary= + Number=$DecNum + while [ $DecNum -ne 0 ] + do + Bit=$(expr $DecNum % 2) + Binary=$Bit$Binary + DecNum=$(expr $DecNum / 2) + done + if [ -z $Binary ]; then + Binary="0000" + fi + len=${#Binary} + while [ $len -lt 4 ] + do + Binary="0"$Binary + len=${#Binary} + done + revstr="" + length=${#Binary} + ii=$((length-1)) + while [ $ii -ge 0 ] + do + revstr=$revstr${Binary:$ii:1} + ii=$((ii-1)) + done + str=$str$revstr + i=$((i-1)) + done + + len=${#str} + ii=0 + lst="" + sep="," + hun=101 + if [ $mod = "1" ]; then + sep=":" + hun=1 + fi + if [ $mod = "2" ]; then + sep="," + hun=1 + fi + while [ $ii -lt $len ] + do + bnd=${str:$ii:1} + if [ $bnd -eq 1 ]; then + if [ $tdec -eq 1 ]; then + jj=$((ii+hun)) + else + if [ $ii -lt 9 ]; then + jj=$((ii+501)) + else + jj=$((ii+5001)) + fi + fi + if [ -z "$lst" ]; then + lst=$jj + else + lst=$lst$sep$jj + fi + fi + ii=$((ii+1)) + done + if [ -z $lst ]; then + lst="0" + fi +} + +encode() { + maskz=$1 + length=${#maskz} + i=0 + ii=1 + lst="" + ij=$((length-1)) + while [ $i -le $ij ] + do + dgt=${maskz:$i:1} + if [ $dgt == "1" ]; then + lst=$lst$ii" " + fi + i=$((i+1)) + ii=$((ii+1)) + done + maskz=$(encodemask $lst) + maskz=$(echo $maskz | sed 's/^0*//') +} + +maskx=$1 +mask64=$(echo "$maskx""," | cut -c1-64 | cut -d, -f1) +maskl2=$(echo ${maskx:64}"," | cut -d, -f1) +maskc=$(echo "$maskx" | grep ",") +if [ ! -z "$maskc" ]; then + mask=$(echo $maskx"," | cut -d, -f1) + mask5g=$(echo $maskx"," | cut -d, -f2) + mask5gsa=$(echo $maskx"," | cut -d, -f3) +else + mask=$maskx + mask5g="" + mask5gsa="" +fi + +#log "$mask" +#log "$mask5g" +#log "$mask5gsa" + +encode $mask +mask=$maskz +encode $mask5g +mask5g=$maskz +encode $mask5gsa +mask5gsa=$maskz +encode $mask64 +mask64=$maskz +encode $maskl2 +if [ -z $maskz ]; then + maskl2="0" +else + maskl2=$maskz +fi +if [ -z $mask64 ]; then + mask64="0" +fi + +if [ -z "$2" ]; then + CURRMODEM=$(uci get modem.general.miscnum) +else + CURRMODEM=1 +fi +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) +CPORT=$(uci -q get modem.modem$CURRMODEM.commport) +model=$(uci get modem.modem$CURRMODEM.model) +uVid=$(uci get modem.modem$CURRMODEM.uVid) +uPid=$(uci get modem.modem$CURRMODEM.uPid) +GW=$(uci -q get modem.modem$CURRMODEM.GW) + +export TIMEOUT="5" +case $uVid in + "2c7c" ) + MODT="1" + if [ -z "$2" ]; then + RESTART="1" + fi + M5="" + M2='AT+QCFG="band",0,'$mask',0,1' + if [ $uPid = 0620 ]; then + EM20=$(echo $model | grep "EM20") + if [ -z "$EM20" ]; then #EM160 + if [ ! -z $mask ]; then + fibdecode $mask 1 1 + else + lst="0" + fi + M2='AT+QNWPREFCFG="lte_band",'$lst + else # Fake EM160 RM500 + if [ -e /etc/qfake ]; then + if [ ! -z $mask ]; then + fibdecode $mask 1 1 + else + lst="0" + fi + M2F='AT+QNWPREFCFG="lte_band",'$lst + if [ ! -z $mask5g ]; then + fibdecode $mask5g 1 1 + else + lst="0" + fi + M5F='AT+QNWPREFCFG="nsa_nr5g_band",'$lst + NET=$(uci -q get modem.modem$CURRMODEM.netmode) + if [ $NET = "9" ]; then + M5F='AT+QNWPREFCFG="nr5g_band",'$lst + fi + log " " + log "Fake LTE Locking Cmd : $M2F" + log "Fake 5G Locking Cmd : $M5F" + log " " + #rm -f /tmp/bmask + exit 0 + fi + fi + fi + if [ $uPid = 030b ]; then + if [ ! -z $mask ]; then + fibdecode $mask 1 1 + else + lst="0" + fi + M2='AT+QNWPREFCFG="lte_band",'$lst + fi + if [ $uPid = 0306 ]; then + RESTART="1" + fi + if [ $uPid = 0800 -o $uPid = 0900 -o $uPid = 0801 ]; then + if [ ! -z "$mask" ]; then + fibdecode $mask 1 1 + else + lst="0" + fi + M2='AT+QNWPREFCFG="lte_band",'$lst + if [ ! -z "$mask5g" ]; then + fibdecode $mask5g 1 1 + else + lst="0" + fi + M5='AT+QNWPREFCFG="nsa_nr5g_band",'$lst + if [ ! -z "$mask5gsa" ]; then + fibdecode $mask5gsa 1 1 + else + lst="0" + fi + M6='AT+QNWPREFCFG="nr5g_band",'$lst + fi + log " " + log "Locking Cmd : $M2" + log "Locking Cmd : $M5" + log "Locking Cmd : $M6" + log " " + + ATCMDD="AT" + NOCFUN=$uVid + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M2") + if [ ! -z "$M5" ]; then + OX5=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M5") + fi + if [ ! -z "$M6" ]; then + OX6=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M6") + fi + log "Locking Cmd Response : $OX" + log "Locking Cmd Response : $OX5" + log "Locking Cmd Response : $OX6" + log " " + if [ $RESTART = "1" ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + sleep 10 + fi + ;; + "1199" ) + MODT="0" + M1='AT!ENTERCND="A710"' + if [ -z $mask64 ]; then + mask64="0" + fi + case $uPid in + + "68c0"|"9041"|"901f" ) # MC7354 EM/MC7355 + M2='AT!BAND=11,"Test",0,'$mask64,0 + ;; + "9070"|"9071"|"9078"|"9079"|"907a"|"907b" ) # EM/MC7455 + M2='AT!BAND=11,"Test",0,'$mask64,0 + if [ -e /etc/fake ]; then + M2='AT!BAND=11,"Test",0,'$mask64','$maskl2',0,0,0' + fi + ;; + "9090"|"9091"|"90b1" ) + M2='AT!BAND=11,"Test",0,'$mask64','$maskl2',0,0,0' + ;; + esac + log "$M2" + if [ -e /etc/fake ]; then + exit 0 + fi + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M1") + log "$OX" + ATCMDD="AT+CFUN=1,1" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M2") + log "$OX" + M2='AT!BAND=00;!BAND=11' + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M2") + log "$OX" + if [ $RESTART = "1" ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ATCMDD='AT!ENTERCND="AWRONG"' + fi + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ;; + "8087"|"2cb7" ) + MODT="2" + FM150="" + if [ $uVid = 2cb7 ]; then + FM150=$(echo $model | grep "FM150") + if [ -z $FM150 ]; then + COMM="XACT" + else + COMM="GTACT" + fi + else + COMM="XACT" + fi + ATCMDD='AT+'$COMM'?' + log " " + log " Get Current Bands : $ATCMDD" + log " " + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + log " " + log " Get Current Bands Response : $OX" + log " " + + lte="" + if [ ! -z $mask ]; then + fibdecode $mask 1 0 + lte=","$lst + fi + L1="4,2,1" + lst="" + if [ ! -z $FM150 ]; then + L1="17,6," + if [ ! -z $mask5g ]; then + fibdecode $mask5g 5 0 + lst=","$lst + else + L1="4,3," + fi + fi + ATCMDD="AT+""$COMM"="$L1$lte$lst" + log " " + log "Lock Command : $ATCMDD" + log " " + + #exit 0 + + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + log " " + log "Lock Response : $OX" + log " " + if [ $RESTART = "1" ]; then + ATCMDD="AT+CFUN=1,1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + ;; + "413c" ) + MODT="3" + case $uPid in + + "81d7"|"81d8"|"e0b4" |"e0b5"|"1910") + if [ ! -z $mask ]; then + fibdecode $mask 1 2 + ATCMDD="AT^SLBAND=LTE,2,""$lst" + log "$ATCMDD" + else + exit 0 + fi + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + log " " + log "Lock Response : $OX" + log " " + if [ $RESTART = "1" ]; then + ATCMDD="AT+CFUN=1,1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + ;; + esac + ;; + * ) + exit 0 + ;; +esac + +if [ $RESTART = "0" ]; then + /usr/lib/rooter/connect/bandmask $CURRMODEM $MODT + exit 0 +fi +rm -f /tmp/bmask +/usr/lib/rooter/luci/restart.sh $CURRMODEM +exit 0 diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/luaops.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/luaops.sh new file mode 100644 index 0000000..b05855f --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/luaops.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +COMMAND=$1 +FILE=$2 + +if [ $COMMAND = delete ]; then + rm -f $FILE +fi \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/mask.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/mask.sh new file mode 100644 index 0000000..5c92692 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/mask.sh @@ -0,0 +1,332 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + modlog "BandMasking $CURRMODEM" "$@" +} + +# +# remove for band locking +# +enb=$(uci -q get custom.bandlock.enabled) +if [ $enb == "0" ]; then + exit 0 +fi + +reverse() { + LX=$1 + length=${#LX} + jx="${LX:2:length-2}" + length=${#jx} + str="" + i=$((length-1)) + while [ $i -ge 0 ] + do + dgt="0x"${jx:$i:1} + DecNum=`printf "%d" $dgt` + Binary= + Number=$DecNum + while [ $DecNum -ne 0 ] + do + Bit=$(expr $DecNum % 2) + Binary=$Bit$Binary + DecNum=$(expr $DecNum / 2) + done + if [ -z $Binary ]; then + Binary="0000" + fi + len=${#Binary} + while [ $len -lt 4 ] + do + Binary="0"$Binary + len=${#Binary} + done + revstr="" + length=${#Binary} + ii=$((length-1)) + while [ $ii -ge 0 ] + do + revstr=$revstr${Binary:$ii:1} + ii=$((ii-1)) + done + str=$str$revstr + i=$((i-1)) + done + revstr=$str"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +} + +rm -f /tmp/bmask +CURRMODEM=$(uci get modem.general.miscnum) +CPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) +uVid=$(uci get modem.modem$CURRMODEM.uVid) +uPid=$(uci get modem.modem$CURRMODEM.uPid) +ATCMDD="AT+CGMM" +model=$($ROOTER/gcom/gcom-locked "$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +L1=$(uci -q get modem.modem$CURRMODEM.L1) +L5=$(uci -q get modem.modem$CURRMODEM.L5) +L6=$(uci -q get modem.modem$CURRMODEM.L6) + +if [ ! $L1 ]; then + exit 0 +fi + +CA3="" +M5="x" +M6="x" +case $uVid in + "2c7c" ) + case $uPid in + "0125" ) # EC25 + #EUX EC25EUXGAR B1/B3/B7/B8/B20/B28A/B38/B40/B41 + #EU EC25EUGAR B1/B3/B7/B8/B20/B28A/B38/B40/B41 + #EC EC25ECGAR + #E EC25EFAR B1/B3/B5/B7/B8/B20/B38/B40/B41 + #AU EC25AUGCR + #AF-FD EC25AFFDR B2/B4/B5/B12/B13/B14/B66/B71 + #AF EC25AFFAR B2/B4/B5/B12/B13/B14/B66/B71 + #A EC25AFAR + CA="" + M1='ATI' + OX=$($ROOTER/gcom/gcom-locked "$CPORT" "run-at.gcom" "$CURRMODEM" "$M1") + REV=$(echo $OX" " | grep -o "Revision: .\+ OK " | tr " " ",") + MODL=$(echo $REV | cut -d, -f2) + EC25AF=$(echo $MODL | grep "EC25AFF") + if [ ! -z "$EC25AF" ]; then # EC25-AF + M2='01011000000111000000000000000000000000000000000000000000000000000100001' + else + EC25AF=$(echo $MODL | grep "EC25E") + if [ ! -z "$EC25AF" ]; then # EC25-E + M2='1010101100000000000100000000000000000101100' + else + EC25AF=$(echo $MODL | grep "EC25AU") + if [ ! -z "$EC25AF" ]; then # EC25-AU + M2='111110110000000000000000000100000000000100' + else # EC25-A + M2='01010000000100' + fi + fi + fi + ;; + "0306" ) # EP06-A + M1='AT+GMR' + OX=$($ROOTER/gcom/gcom-locked "$CPORT" "run-at.gcom" "$CURRMODEM" "$M1") + EP06E=$(echo $OX | grep "EP06E") + if [ ! -z "$EP06E" ]; then # EP06E + M2='101010110000000000010000000100010000010110' + CA="ep06e-bands" + else # EP06A + M2='010110100001100010000000110011000000000010000000000000000000000001' + CA="ep06a-bands" + fi + ;; + "030b" ) # EM060 + M2='111110110001110001110000110111000100011111100101000000000000000001000010' + CA="em060-2xbands" + CA3="" + ;; + "0512" ) # EM12-G + EM12=$(echo $model | grep "EG18") + if [ -z "$EM12" ]; then + M2='111110111001110011111000110111010000011110000000000000000000000001' + CA="em12-2xbands" + CA3="em12-3xbands" + else # EG18 + EM12=$(echo $model | grep "EA") + if [ -z "$EM12" ]; then # NA + M2='01011001000111001000000011001100000000001000000000000000000000000000001000010' + else # EA + M2='101010110000000000010000000100000000010110' + fi + CA="" + CA3="" + fi + ;; + "0620" ) # EM20-G + EM20=$(echo $model | grep "EM20") + if [ ! -z "$EM20" ]; then + M2='111110110001110011110000110111000000011111100101000000000000000001' + CA="em20-2xbands" + CA3="em20-3xbands" + CA4="em20-4xbands" + if [ -e /etc/qfake ]; then + M2='1111101100011100011100001101110101000111111000010000000000000000010000100' + M5='0000000000000000000000000000000000000100100000000000000000000000000000000000111' + M6='1110101100010000000100001001000000000101100000010000000000000000010000100000111' + $ROOTER/luci/celltype.sh $CURRMODEM + NET=$(uci -q get modem.modem$CURRMODEM.netmode) + if [ $NET != "7" ]; then + M5=$M6 # SA mode + L5=$L6 + fi + CA="" + CA3="" + CA4="" + fi + + else + M2='111110110001110011110000110111010000011111100101000000000000000001' + CA="em20-2xbands" + CA3="em20-3xbands" + CA4="em20-4xbands" + fi + ;; + "0801" ) #RM520 + GL=$(echo $model | grep "GL") + if [ ! -z "$GL" ]; then #RM520N-GL + M2='1111101100011100111100001101110101000111111001010000000000000000010000100' + M5='11101011000111000101000011011100000001011000000100000000000000000100011000111110' + M6=$M5 + CA="" + CA3="" + else #RM520N-EU + M2='1010101100000000000100000001000100000101111001000000000000000000000000100' + M5='101010110000000000010000000100000000010110000000000000000000000000000010001111' + M6=$M5 + CA="" + CA3="" + fi + ;; + "0900" ) + M2='111010110000000000010000000100000100011110' + M5='1000000000000000000000000001000000000000100000000000000000000000000000000000111' + M6=$M5 + CA="" + CA3="" + ;; + "0800") # RM500 + f2=$(echo $model | grep "500") + if [ -z "$f2" ]; then #RM502/505/510 + M2='1111101100011100011100001101110101000111111001010000000000000000010000100' + M5='1110101100010100000100001001000000000101100000010000000000000000010000100000111' + M6=$M5 + else + GL=$(echo $model | grep "GL") + if [ ! -z "$GL" ]; then #RM500-GL + M2='1111101100011100111100001101110101000111111001010000000000000000010000100' + M5='0000000000000000000000000000000000000000100000000000000000000000000000000000111' + M6='1110101100010000000100001001000000000101100000010000000000000000010000100000111' + else # RM500-AE + M2='1111101100011100011100001101110101000111111001010000000000000000010000100' + M5='11101011000100000001000010010000000001011000000100000000000000000100001000001110' + M6=$M5 + fi + fi + CA="" + CA3="" + ;; + esac + ;; + "1199" ) + case $uPid in + "68a2" ) # MC7700 + M2='1001000000000000100000000' + CA="" + ;; + "68c0"|"9041"|"901f" ) # MC7354 EM/MC7355 + M2='0101100000001000100000001' + CA="" + ;; + "9070"|"9071"|"9078"|"9079"|"907a"|"907b" ) # EM/MC7455 + M2='11111011000110000001000011000100000000001' + if [ -e /etc/fake ]; then + M2='1111101100011100011100000100110100000000110001010000000000000000010' + fi + CA="mc7455-bands" + ;; + "9090"|"9091"|"90b1" ) + EM7565=$(echo "$model" | grep "7565") + if [ ! -z "$EM7565" ]; then # EM7565 + M2='111110111001100001110000010111010000000011100101000000000000000001' + CA="em7565-2xbands" + CA3="em7565-3xbands" + else + EM7511=$(echo "$model" | grep "7511") + if [ ! -z "$EM7511" ]; then # EM7511 + M2='1111101100011100011100000100110100000000110001010000000000000000010' + CA="em7511-2xbands" + CA3="em7511-3xbands" + else # EM7411 + M2='0101101000011100000000001100000000000000111000010000000000000000010000100' + CA="em7411-2xbands" + CA3="em7411-3xbands" + fi + fi + ;; + esac + ;; + "8087" ) + M2='111110110001100011110000010111000000011110000000000000000000000001' + CA="l850-2xbands" + CA3="l850-3xbands" + ;; + "2cb7" ) + FM150=$(echo "$model" | grep "FM150") + if [ -z "$FM150" ]; then + M2='111110110001100011110000010111000000011110000000000000000000000001' + CA="l850-2xbands" + CA3="l850-3xbands" + else + M2='01011000000100000000000010001100000000000000000000000000000000000100001' + M5='00001000000100000000000000000000000000001000000000000000000000000100001' + CA="" + CA3="" + fi + ;; + "413c" ) + case $uPid in + + "81d7"|"81d8"|"e0b4" |"e0b5"|"1910") + M2='11111011000111001111000011011101000001111110010100000000000000000100' + CA="" + CA3="" + ;; + esac + ;; + "1bc7" ) + case $uPid in + + "1040"|"1041") + L1X=$(uci -q get modem.modem$CURRMODEM.L1X) + M2=$L1X + CA="" + CA3="" + ;; + esac + ;; + * ) + exit 0 + ;; +esac + +reverse $L1 +echo $revstr > /tmp/bmask1 +if [ ! -z $L5 ]; then + reverse $L5 +else + revstr="x" +fi +echo $revstr >> /tmp/bmask1 +if [ ! -z $L6 ]; then + reverse $L6 +else + revstr="x" +fi +echo $revstr >> /tmp/bmask1 +echo $M2 >> /tmp/bmask1 +echo $M5 >> /tmp/bmask1 +if [ -z "$M6" ]; then + M6="x" +fi +echo $M6 >> /tmp/bmask1 +if [ $CA ]; then + echo $CA >> /tmp/bmask1 + if [ $CA3 ]; then + echo $CA3 >> /tmp/bmask1 + if [ $CA4 ]; then + echo $CA4 >> /tmp/bmask1 + fi + fi +fi +mv /tmp/bmask1 /tmp/bmask + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/mc7455-bands b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/mc7455-bands new file mode 100644 index 0000000..3114071 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/mc7455-bands @@ -0,0 +1,14 @@ +1 8 +2 2 +2 5 +2 12 +2 13 +3 7 +3 20 +4 4 +4 5 +4 12 +4 13 +7 7 +7 20 +41 41 \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/modechge.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/modechge.sh new file mode 100644 index 0000000..7c5ec76 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/modechge.sh @@ -0,0 +1,276 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +MODEMTYPE=$1 +NETMODE=$2 + +# log() { + modlog "ModeChange $CURRMODEM" "$@" +# } + +CURRMODEM=$(uci get modem.general.modemnum) +uci set modem.modem$CURRMODEM.cmode="0" +uci set modem.modem$CURRMODEM.netmode="10" +uci commit modem + +MODEMTYPE=$(uci get modem.modem$CURRMODEM.modemtype) +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) + +# ZTE +if [ $MODEMTYPE -eq 1 ]; then + case $NETMODE in + 1*) + ATC="AT+ZSNT=0,0,0" ;; + 2*) + ATC="AT+ZSNT=0,0,1" ;; + 3*) + ATC="AT+ZSNT=1,0,0" ;; + 4*) + ATC="AT+ZSNT=0,0,2" ;; + 5*) + ATC="AT+ZSNT=2,0,0" ;; + 6*) + ATC="AT+ZSNT=0,0,6" ;; + 7*) + ATC="AT+ZSNT=6,0,0" ;; + esac + ATC=$ATC";+ZBANDI=0" +fi + +# Sierra +if [ $MODEMTYPE -eq 2 ]; then + case $NETMODE in + "3" ) + ATC="AT!SELRAT=2" ;; + "5" ) + ATC="AT!SELRAT=1" ;; + "7" ) + ATC="AT!SELRAT=6" ;; + * ) + ATC="AT!SELRAT=0" ;; + esac +fi + +# Huawei LTE +if [ $MODEMTYPE -eq 3 ]; then + case $NETMODE in + 1*) + ATC="AT^SYSCFGEX=\"00\",40000000,2,4,40000000,," ;; + 2*) + ATC="AT^SYSCFGEX=\"010203\",40000000,2,4,40000000,," ;; + 3*) + ATC="AT^SYSCFGEX=\"01\",40000000,2,4,40000000,," ;; + 4*) + ATC="AT^SYSCFGEX=\"020301\",40000000,2,4,40000000,," ;; + 5*) + ATC="AT^SYSCFGEX=\"02\",40000000,2,4,40000000,," ;; + 6*) + ATC="AT^SYSCFGEX=\"030201\",40000000,2,4,40000000,," ;; + 7*) + ATC="AT^SYSCFGEX=\"03\",40000000,2,4,40000000,," ;; + esac +fi + +# Huawei legacy +if [ $MODEMTYPE -eq 4 ]; then + case $NETMODE in + 1*) + ATC="AT^SYSCFG=2,0,40000000,2,4" ;; + 2*) + ATC="AT^SYSCFG=2,1,40000000,2,4" ;; + 3*) + ATC="AT^SYSCFG=13,1,40000000,2,4" ;; + 4*) + ATC="AT^SYSCFG=2,2,40000000,2,4" ;; + 5*) + ATC="AT^SYSCFG=14,2,40000000,2,4" ;; + esac +fi + +# ublox +if [ $MODEMTYPE -eq 5 ]; then + case $NETMODE in + 1*) + ATC="AT+CFUN=4;+URAT=4,3;+CFUN=1,1" ;; + 2*) + ATC="AT+CFUN=4;+URAT=4,0;+CFUN=1,1" ;; + 3*) + ATC="AT+CFUN=4;+URAT=0;+CFUN=1,1" ;; + 4*) + ATC="AT+CFUN=4;+URAT=4,2;+CFUN=1,1" ;; + 5*) + ATC="AT+CFUN=4;+URAT=2;+CFUN=1,1" ;; + 6*) + ATC="AT+CFUN=4;+URAT=4,3;+CFUN=1,1" ;; + 7*) + ATC="AT+CFUN=4;+URAT=4,3;+CFUN=1,1" ;; + esac +fi + +# Quectel +if [ $MODEMTYPE -eq 6 ]; then + CURRMODEM=$(uci -q get modem.general.modemnum) + idV=$(uci -q get modem.modem$CURRMODEM.idV) + idP=$(uci -q get modem.modem$CURRMODEM.idP) + ATCMDD="AT+CGMM" + model=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + EM20=$(echo "$model" | grep "EM20") + if [ $EM20 ]; then + idP="0" + fi + NEWFMT=false + if [ "$idV" = "2c7c" ]; then + if [ "$idP" = "0800" -o "$idP" = "0620" -o "$idP" = "030b" -o "$idP" = "0801" -o "$idP" = "0900" ]; then + NEWFMT=true + fi + fi + case $NETMODE in + "3") + ATC="AT+QCFG=\"nwscanmode\",1" ;; + "5") + if $NEWFMT; then + ATC="AT+QNWPREFCFG=\"mode_pref\",WCDMA" + else + ATC="AT+QCFG=\"nwscanmode\",2" + fi + ;; + "7") + if $NEWFMT; then + ATC="AT+QNWPREFCFG=\"mode_pref\",LTE" + else + ATC="AT+QCFG=\"nwscanmode\",3" + fi + ;; + "8") + ATC="AT+QNWPREFCFG=\"mode_pref\",LTE:NR5G" ;; + "9") + ATC="AT+QNWPREFCFG=\"mode_pref\",NR5G" ;; + *) + if $NEWFMT; then + ATC="AT+QNWPREFCFG=\"mode_pref\",AUTO" + else + ATC="AT+QCFG=\"nwscanmode\",0" + fi + ;; + esac +fi + +# MEIG +if [ $MODEMTYPE -eq 7 ]; then + CURRMODEM=$(uci -q get modem.general.modemnum) + idV=$(uci -q get modem.modem$CURRMODEM.idV) + if [ $idV == "2dee" ]; then + case $NETMODE in + "4") + ATC="AT^SYSCFGEX=\"020304\"" ;; + "5") + ATC="AT^SYSCFGEX=\"02\"" ;; + "6") + ATC="AT^SYSCFGEX=\"030402\"" ;; + "7") + ATC="AT^SYSCFGEX=\"03\"" ;; + "8") + ATC="AT^SYSCFGEX=\"0403\"" ;; + "9") + ATC="AT^SYSCFGEX=\"04\"" ;; + *) + ATC="AT^SYSCFGEX=\"00\"" ;; + esac + else + case $NETMODE in + "3") + ATC="AT+MODODR=3" ;; + "5") + ATC="AT+MODODR=1" ;; + "7") + ATC="AT+MODODR=5" ;; + *) + ATC="AT+MODODR=2" ;; + esac + fi +fi + +# Telit, Foxconn, etc. +if [ $MODEMTYPE -eq 8 ]; then + case $NETMODE in + "3" ) + ATC="AT\$QCNSP=1,0,0" ;; + "5" ) + ATC="AT\$QCNSP=2,0,0" ;; + "7" ) + ATC="AT\$QCNSP=6,0,0" ;; + * ) + ATC="AT\$QCNSP=0,0,0" ;; + esac +fi + +# Fibocom +if [ $MODEMTYPE -eq 9 ]; then + CURRMODEM=$(uci -q get modem.general.modemnum) + idV=$(uci -q get modem.modem$CURRMODEM.idV) + idP=$(uci -q get modem.modem$CURRMODEM.idP) + idPP=${idP:1:1} + if [ "$idPP" = "1" ]; then + case $NETMODE in + "7") + ATC="AT+GTRAT=3" ;; + "8") + ATC="AT+GTRAT=17" ;; + "9") + ATC="AT+GTRAT=14" ;; + *) + ATC="AT+GTRAT=10" ;; + esac + else + case $NETMODE in + "4") + ATC="AT+XACT=4,1" ;; + "5") + ATC="AT+XACT=1" ;; + "7") + ATC="AT+XACT=2" ;; + *) + ATC="AT+XACT=4,2" ;; + esac + fi +fi + +# SIMCom +if [ $MODEMTYPE -eq 10 ]; then + case $NETMODE in + "3") + ATC="AT+CNMP=13" ;; + "5") + ATC="AT+CNMP=14" ;; + "7") + ATC="AT+CNMP=38" ;; + "8") + ATC="AT+CNMP=109" ;; + "9") + ATC="AT+CNMP=71" ;; + *) + ATC="AT+CNMP=1" ;; + esac +fi + +# Quanta, Megafon +if [ $MODEMTYPE -eq 11 ]; then + case $NETMODE in + "5") + ATC="AT^QCNCFG=02" ;; + "7") + ATC="AT^QCNCFG=03" ;; + *) + ATC="AT^QCNCFG=00" ;; + esac +fi + +ATCMDD="$ATC" +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + +$ROOTER/luci/celltype.sh $CURRMODEM +uci set modem.modem$CURRMODEM.cmode="1" +uci commit modem + +$ROOTER/luci/restart.sh $CURRMODEM diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/modemchge.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/modemchge.sh new file mode 100644 index 0000000..a0fd3e9 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/modemchge.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +TYPE=$1 +DIREC=$2 +source /tmp/modcnt +MODCNT=$MODCNTX + +case $TYPE in +"modem" ) + MODENUM=$(uci get modem.general.modemnum) + ;; +"sms" ) + MODENUM=$(uci get modem.general.smsnum) + ;; +"misc" ) + MODENUM=$(uci get modem.general.miscnum) + ;; +esac + +if [ $DIREC -eq 1 ]; then + let MODENUM=MODENUM+1 + if [ $MODENUM -gt $MODCNT ]; then + MODENUM=1 + fi +else + if [ $MODENUM -eq 1 ]; then + MODENUM=$MODCNT + else + let MODENUM=MODENUM-1 + fi +fi +case $TYPE in +"modem" ) + uci set modem.general.modemnum=$MODENUM + ;; +"sms" ) + uci set modem.general.smsnum=$MODENUM + ;; +"misc" ) + uci set modem.general.miscnum=$MODENUM + uci commit modem + /usr/lib/rooter/luci/mask.sh + ;; +esac +uci commit modem + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/portchge.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/portchge.sh new file mode 100644 index 0000000..928b60d --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/portchge.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +DIR=$1 + +log() { + modlog "Port change $CURRMODEM" "$@" +} + + +CURRMODEM=$(uci get modem.general.modemnum) +BASEP=$(uci get modem.modem$CURRMODEM.baseport) +MAXP=$(uci get modem.modem$CURRMODEM.maxport) +PORT=$(uci get modem.modem$CURRMODEM.commport) + +log "$DIR" + +if [ $DIR = "up" ]; then + if [ $PORT -lt $MAXP ]; then + PORT=`expr $PORT + 1` + echo 'PORT="'"$PORT"'"' > /tmp/port$CURRMODEM.file + fi +else + if [ $PORT -gt $BASEP ]; then + PORT=`expr $PORT - 1` + echo 'PORT="'"$PORT"'"' > /tmp/port$CURRMODEM.file + fi +fi + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/protochnge.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/protochnge.sh new file mode 100644 index 0000000..d6d8ff8 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/protochnge.sh @@ -0,0 +1,155 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +NEWMOD=$1 + + log() { + modlog "ProtoChange $CURRMODEM" "$@" + } + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + + change_bconf() { + local devname=$1 + local conf=$2 + local mode=$3 + local unconf=0 + log "Switching Modem at $devname to $mode by selecting Cfg# $conf" + echo $unconf >/sys/bus/usb/devices/$devname/bConfigurationValue + sleep 1 + echo $conf >/sys/bus/usb/devices/$devname/bConfigurationValue +} + + chkT77() { + T77=0 + if [ $idV = 413c -a $idP = 81d7 ]; then + T77=1 + elif [ $idV = 413c -a $idP = 81d8 ]; then + T77=1 + elif [ $idV = 0489 -a $idP = e0b4 ]; then + T77=1 + elif [ $idV = 0489 -a $idP = e0b5 ]; then + T77=1 + elif [ $idV = 1bc7 -a $idP = 1910 ]; then + T77=1 + fi +} + + chksierra() { + SIERRAID=0 + if [ $idV = 1199 ]; then + case $idP in + "68aa"|"68a2"|"68a3"|"68a9"|"68b0"|"68b1" ) + SIERRAID=1 + ;; + "68c0"|"9040"|"9041"|"9051"|"9054"|"9056"|"90d3" ) + SIERRAID=1 + ;; + "9070"|"907b"|"9071"|"9079"|"901c"|"9091"|"901f"|"90b1" ) + SIERRAID=1 + ;; + esac + elif [ $idV = 114f -a $idP = 68a2 ]; then + SIERRAID=1 + elif [ $idV = 413c -a $idP = 81a8 ]; then + SIERRAID=1 + elif [ $idV = 413c -a $idP = 81b6 ]; then + SIERRAID=1 + fi +} + +chkquectel() { + QUECTEL=false + if [ "$idV" = "2c7c" ]; then + QUECTEL=true + elif [ "$idV" = "05c6" ]; then + QUELST="9090,9003,9215" + if [[ $(echo "$QUELST" | grep -o "$idP") ]]; then + QUECTEL=true + fi + fi +} + +log "Protocol Change to $NEWMOD" + +CURRMODEM=$(uci get modem.general.modemnum) +CPORT=$(uci get modem.modem$CURRMODEM.commport) +idV=$(uci get modem.modem$CURRMODEM.uVid) +idP=$(uci get modem.modem$CURRMODEM.uPid) + +chkquectel +if $QUECTEL; then + case $NEWMOD in + "1" ) + ATCMDD='AT+QCFG="usbnet",0' + ;; + "2" ) + ATCMDD='AT+QCFG="usbnet",2' + ;; + "3" ) + ATCMDD='AT+QCFG="usbnet",1' + ;; + esac + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +fi + + chksierra + if [ $SIERRAID -eq 1 ]; then + ATCMDD='AT!ENTERCND="A710"' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + + case $idP in + "68c0"|"9041"|"901f" ) # MC7354 EM/MC7355 + case $NEWMOD in + "1" ) + ATCMDD='at!UDUSBCOMP=6' + ;; + "2" ) + ATCMDD='at!UDUSBCOMP=8' + ;; + esac + ;; + "9070"|"9071"|"9078"|"9079"|"907a"|"907b" ) # EM/MC7455 + case $NEWMOD in + "1" ) + ATCMDD='at!usbcomp=1,1,10d' + ;; + "2" ) + ATCMDD='at!usbcomp=1,1,1009' + ;; + esac + ;; + "9090"|"9091"|"90b1" ) # EM7565 + case $NEWMOD in + "1" ) + ATCMDD='at!usbcomp=1,3,10d' + ;; + "2" ) + ATCMDD='AT!USBCOMP=1,3,1009' + ;; + esac + ;; + esac + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ATCMDD='AT!ENTERCND="AWRONG"' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + + chkT77 + if [ $T77 = "1" ]; then + DEVICE=$(uci get modem.modem$CURRMODEM.device) + if [ $NEWMOD = "1" ]; then + change_bconf $DEVICE 1 QMI + else + change_bconf $DEVICE 2 MBIM + fi + log "T77 $NEWMOD $DEVICE" + fi +sleep 5 + +/usr/lib/rooter/luci/restart.sh $CURRMODEM + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/restart.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/restart.sh new file mode 100644 index 0000000..dbbe377 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/restart.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "Modem Restart/Diisconnect $CURRMODEM" "$@" +} + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + +CURRMODEM=$1 +CPORT=$(uci -q get modem.modem$CURRMODEM.commport) +INTER=$(uci get modem.modeminfo$CURRMODEM.inter) + +if [ ! -z "$2" ]; then # disconnect + uci set modem.modem$CURRMODEM.connected=0 + uci commit modem + jkillall getsignal$CURRMODEM + rm -f $ROOTER_LINK/getsignal$CURRMODEM + jkillall con_monitor$CURRMODEM + rm -f $ROOTER_LINK/con_monitor$CURRMODEM + ifdown wan$INTER + $ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "reset.gcom" "$CURRMODEM" +else # restart + uVid=$(uci get modem.modem$CURRMODEM.uVid) + uPid=$(uci get modem.modem$CURRMODEM.uPid) + #if [ $uVid != "2c7c" ]; then + if [ ! -z "$CPORT" ]; then + ATCMDD="AT+CFUN=1,1" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + fi + log "Hard modem reset done" + #fi + ifdown wan$INTER + uci delete network.wan$CURRMODEM + uci set network.wan$CURRMODEM=interface + uci set network.wan$CURRMODEM.proto=dhcp + uci set network.wan$CURRMODEM.${ifname1}="wan"$CURRMODEM + uci set network.wan$CURRMODEM.metric=$CURRMODEM"0" + uci commit network + /etc/init.d/network reload + echo "1" > /tmp/modgone + log "Hard USB reset done" + + PORT="usb$CURRMODEM" + echo $PORT > /sys/bus/usb/drivers/usb/unbind + sleep 35 + echo $PORT > /sys/bus/usb/drivers/usb/bind +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/scancmd.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/scancmd.sh new file mode 100644 index 0000000..dc6e96d --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/scancmd.sh @@ -0,0 +1,412 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + modlog "Scan Command $CURRMODEM" "$@" +} + +fibdecode() { + j=$1 + tdec=$2 + mod=$3 + length=${#j} + jx=$j + length=${#jx} + + str="" + i=$((length-1)) + while [ $i -ge 0 ] + do + dgt="0x"${jx:$i:1} + DecNum=`printf "%d" $dgt` + Binary= + Number=$DecNum + while [ $DecNum -ne 0 ] + do + Bit=$(expr $DecNum % 2) + Binary=$Bit$Binary + DecNum=$(expr $DecNum / 2) + done + if [ -z $Binary ]; then + Binary="0000" + fi + len=${#Binary} + while [ $len -lt 4 ] + do + Binary="0"$Binary + len=${#Binary} + done + revstr="" + length=${#Binary} + ii=$((length-1)) + while [ $ii -ge 0 ] + do + revstr=$revstr${Binary:$ii:1} + ii=$((ii-1)) + done + str=$str$revstr + i=$((i-1)) + done + len=${#str} + ii=0 + lst="" + sep="," + hun=101 + if [ $mod = "1" ]; then + sep=":" + hun=1 + fi + while [ $ii -lt $len ] + do + bnd=${str:$ii:1} + if [ $bnd -eq 1 ]; then + if [ $tdec -eq 1 ]; then + jj=$((ii+hun)) + else + if [ $ii -lt 9 ]; then + jj=$((ii+501)) + else + jj=$((ii+5001)) + fi + fi + if [ -z $lst ]; then + lst=$jj + else + lst=$lst$sep$jj + fi + fi + ii=$((ii+1)) + done +} + +CURRMODEM=$(uci get modem.general.miscnum) +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) +uVid=$(uci get modem.modem$CURRMODEM.uVid) +uPid=$(uci get modem.modem$CURRMODEM.uPid) +model=$(uci get modem.modem$CURRMODEM.model) +ACTIVE=$(uci get modem.pinginfo$CURRMODEM.alive) +uci set modem.pinginfo$CURRMODEM.alive='0' +uci commit modem +L1=$(uci get modem.modem$CURRMODEM.L1) +length=${#L1} +L1="${L1:2:length-2}" +L1=$(echo $L1 | sed 's/^0*//') +L2=$(uci get modem.modem$CURRMODEM.L2) +L1X=$(uci get modem.modem$CURRMODEM.L1X) +if [ -z $L1X ]; then + L1X="0" +fi + +case $uVid in + "2c7c" ) + M2='AT+QENG="neighbourcell"' + M5="" + case $uPid in + "0125" ) # EC25-A + EC25=$(echo $model | grep "EC25-AF") + if [ ! -z $EC25 ]; then + MX='400000000000003818' + else + MX='81a' + fi + M4='AT+QCFG="band",0,'$MX',0' + ;; + "0306" ) + M1='AT+GMR' + OX=$($ROOTER/gcom/gcom-locked "$CPORT" "run-at.gcom" "$CURRMODEM" "$M1") + EP06E=$(echo $OX | grep "EP06E") + if [ ! -z $EP06E ]; then # EP06E + M3='1a080800d5' + else # EP06-A + M3="2000001003300185A" + fi + M4='AT+QCFG="band",0,'$M3',0' + ;; + "030b" ) # EM060 + M3="420000A7E23B0E38DF" + M4='AT+QCFG="band",0,'$M3',0' + ;; + "0512" ) # EM12-G + EM12=$(echo $model | grep "EG18") + if [ -z "$EM12" ]; then + M3="2000001E0BB1F39DF" + else # EG18 + EM12=$(echo $model | grep "EA") + if [ -z "$EM12" ]; then # NA + M3="4200000100330138A" + else # EA + M3="1A0080800C5" + fi + fi + M4='AT+QCFG="band",0,'$M3',0' + ;; + "0620" ) # EM20-G + EM20=$(echo $model | grep "EM20") + if [ ! -z $EM20 ]; then # EM20 + M3="20000A7E03B0F38DF" + M4='AT+QCFG="band",0,'$M3',0' + if [ -e /etc/qfake ]; then + mask="42000087E2BB0F38DF" + fibdecode $mask 1 1 + M4F='AT+QNWPREFCFG="lte_band",'$lst + log "Fake RM500 $M4F" + fi + + else # EM160 + mask="20000A7E0BB0F38DF" + fibdecode $mask 1 1 + M4='AT+QNWPREFCFG="lte_band",'$lst + fi + ;; + "0800"|"0900"|"0801" ) + + ;; + * ) + M3="AT" + M4='AT+QCFG="band",0,'$M3',0' + ;; + esac + + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M4") + log "$OX" + if [ ! -z $M5 ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M5") + log "$OX" + fi + sleep 5 + ;; + "1199" ) + M2='AT!LTEINFO?' + case $uPid in + + "68c0"|"9041"|"901f" ) # MC7354 EM/MC7355 + M3="101101A" + M3X="0" + M4='AT!BAND=11,"Test",0,'$M3,$M3X + ;; + "9070"|"9071"|"9078"|"9079"|"907a"|"907b" ) # EM/MC7455 + M3="100030818DF" + M3X="0" + M4='AT!BAND=11,"Test",0,'$M3,$M3X + if [ -e /etc/fake ]; then + M4='AT!BAND=11,"Test",0,A300BA0E38DF,2,0,0,0' + fi + ;; + "9090"|"9091"|"90b1" ) # EM7565 + EM7565=$(echo "$model" | grep "7565") + if [ ! -z $EM7565 ]; then + M3="A300BA0E38DF" + M3X="2" + M4='AT!BAND=11,"Test",0,'$M3","$M3X",0,0,0" + else + EM7511=$(echo "$model" | grep "7511") + if [ ! -z $EM7511 ]; then # EM7511 + M3="A300BA0E38DF" + M3X="2" + M4='AT!BAND=11,"Test",0,'$M3","$M3X",0,0,0" + else + M3="87000300385A" + M3X="42" + M4='AT!BAND=11,"Test",0,'$M3","$M3X",0,0,0" + fi + fi + + ;; + * ) + M3="AT" + ;; + esac + log "Set full : $M4" + if [ -e /etc/fake ]; then + M4='AT!BAND=11,"Test",0,'$M3,$M3X + fi + M1='AT!ENTERCND="A710"' + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M1") + log "$OX" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M4") + log "$OX" + M4='AT!BAND=00;!BAND=11' + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M4") + log "$OX" + ATCMDD='AT!ENTERCND="AWRONG"' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ;; + "8087"|"2cb7" ) + rm -f /tmp/scan + echo "Cell Scanner Start ..." > /tmp/scan + echo " " >> /tmp/scan + if [ -e /tmp/scan$CURRMODEM ]; then + SCX=$(cat /tmp/scan$CURRMODEM) + echo "$SCX" >> /tmp/scan + else + echo "No Neighbouring cells were found" >> /tmp/scan + fi + echo " " >> /tmp/scan + echo "Done" >> /tmp/scan + exit 0 + ;; + * ) + rm -f /tmp/scanx + echo "Scan for Neighbouring cells not supported" >> /tmp/scan + uci set modem.pinginfo$CURRMODEM.alive=$ALIVE + uci commit modem + exit 0 + ;; +esac + +export TIMEOUT="10" +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M2") +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M2") +log "$OX" +ERR=$(echo "$OX" | grep "ERROR") +if [ ! -z $ERR ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M2") + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M2") + log "$OX" +fi +if [ ! -z $ERR ]; then + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M2") + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M2") + log "$OX" +fi +log "$OX" +echo "$OX" > /tmp/scanx +rm -f /tmp/scan +echo "Cell Scanner Start ..." > /tmp/scan +echo " " >> /tmp/scan +flg=0 +while IFS= read -r line +do + case $uVid in + "2c7c" ) + qm=$(echo $line" " | grep "+QENG:" | tr -d '"' | tr " " ",") + if [ "$qm" ]; then + INT=$(echo $qm | cut -d, -f3) + BND=$(echo $qm | cut -d, -f5) + PCI=$(echo $qm | cut -d, -f6) + RSSI=$(echo $qm | cut -d, -f9) + BAND=$(/usr/bin/chan2band.sh $BND) + if [ "$INT" = "intra" ]; then + echo "Band : $BAND Signal : $RSSI (dBm) EARFCN : $BND PCI : $PCI (current)" >> /tmp/scan + else + echo "Band : $BAND Signal : $RSSI (dBm) EARFCN : $BND PCI : $PCI" >> /tmp/scan + fi + flg=1 + fi + ;; + "1199" ) + qm=$(echo $line" " | grep "Serving:" | tr -d '"' | tr " " ",") + if [ "$qm" ]; then + read -r line + qm=$(echo $line" " | tr -d '"' | tr " " ",") + BND=$(echo $qm | cut -d, -f1) + PCI=$(echo $qm | cut -d, -f10) + BAND=$(/usr/bin/chan2band.sh $BND) + RSSI=$(echo $qm | cut -d, -f13) + echo "Band : $BAND Signal : $RSSI (dBm) EARFCN : $BND PCI : $PCI (current)" >> /tmp/scan + flg=1 + else + qm=$(echo $line" " | grep "InterFreq:" | tr -d '"' | tr " " ",") + log "$line" + if [ "$qm" ]; then + while [ 1 = 1 ] + do + read -r line + log "$line" + qm="" + qm=$(echo $line" " | grep ":" | tr -d '"' | tr " " ",") + if [ "$qm" ]; then + break + fi + qm=$(echo $line" " | grep "OK" | tr -d '"' | tr " " ",") + if [ "$qm" ]; then + break + fi + qm=$(echo $line" " | tr -d '"' | tr " " ",") + if [ "$qm" = "," ]; then + break + fi + BND=$(echo $qm | cut -d, -f1) + PCI=$(echo $qm | cut -d, -f10) + BAND=$(/usr/bin/chan2band.sh $BND) + RSSI=$(echo $qm | cut -d, -f8) + echo "Band : $BAND Signal : $RSSI (dBm) EARFCN : $BND PCI : $PCI" >> /tmp/scan + flg=1 + done + break + fi + fi + ;; + * ) + + ;; + esac +done < /tmp/scanx + +rm -f /tmp/scanx +if [ $flg -eq 0 ]; then + echo "No Neighbouring cells were found" >> /tmp/scan +fi +echo " " >> /tmp/scan +echo "Done" >> /tmp/scan + +case $uVid in + "2c7c" ) + if [ $uPid != "0800" ]; then + if [ $uPid = 0620 -o $uPid = "0800" -o $uPid = "030b" ]; then + EM20=$(echo $model | grep "EM20") + if [ ! -z $EM20 ]; then # EM20 + M2='AT+QCFG="band",0,'$L1',0' + if [ -e /etc/fake ]; then + fibdecode $L1 1 1 + M2F='AT+QNWPREFCFG="lte_band",'$lst + log "Fake EM160 Band Set "$M2F + fi + else + fibdecode $L1 1 1 + M2='AT+QNWPREFCFG="lte_band",'$lst + fi + else + M4='AT+QCFG="band",0,'$L1',0' + fi + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M4") + log "$OX" + fi + ;; + "1199" ) + M1='AT!ENTERCND="A710"' + case $uPid in + + "68c0"|"9041"|"901f" ) # MC7354 EM/MC7355 + M4='AT!BAND=11,"Test",0,'$L1X,0 + ;; + "9070"|"9071"|"9078"|"9079"|"907a"|"907b" ) # EM/MC7455 + M4='AT!BAND=11,"Test",0,'$L1X,0 + if [ -e /etc/fake ]; then + M4='AT!BAND=11,"Test",0,'$L1X','$L2',0,0,0' + fi + ;; + "9090"|"9091"|"90b1" ) + M4='AT!BAND=11,"Test",0,'$L1X','$L2',0,0,0' + ;; + esac + log "Set back : $M4" + if [ -e /etc/fake ]; then + M4='AT!BAND=11,"Test",0,00000100030818DF,0' + fi + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M1") + log "$OX" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M4") + log "$OX" + M4='AT!BAND=00;!BAND=11' + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$M4") + log "$OX" + ATCMDD='AT!ENTERCND="AWRONG"' + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + ;; +esac +uci set modem.pinginfo$CURRMODEM.alive=$ACTIVE +uci commit modem + +log "Finished Scan" diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/setcell.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/setcell.sh new file mode 100644 index 0000000..8eadd81 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/setcell.sh @@ -0,0 +1,72 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + modlog "Lock Cell $CURRMODEM" "$@" +} + +dat="$1" + +CURRMODEM=$(uci -q get modem.general.miscnum) + +dat1=$(echo $dat | tr "|" ",") +dat2=$(echo $dat1 | cut -d, -f1) +if [ $dat2 = "0" ]; then + uci set custom.bandlock.cenable$CURRMODEM='0' +else + ear=$(echo $dat1 | cut -d, -f2) + pc=$(echo $dat1 | cut -d, -f3) + ear1=$(echo $dat1 | cut -d, -f4) + pc1=$(echo $dat1 | cut -d, -f5) + ear2=$(echo $dat1 | cut -d, -f6) + pc2=$(echo $dat1 | cut -d, -f7) + ear3=$(echo $dat1 | cut -d, -f8) + pc3=$(echo $dat1 | cut -d, -f9) + uci set custom.bandlock.cenable$CURRMODEM='1' + uci set custom.bandlock.earfcn$CURRMODEM=$ear + uci set custom.bandlock.pci$CURRMODEM=$pc + uci set custom.bandlock.earfcn1$CURRMODEM=$ear1 + uci set custom.bandlock.pci1$CURRMODEM=$pc1 + uci set custom.bandlock.earfcn2$CURRMODEM=$ear2 + uci set custom.bandlock.pci2$CURRMODEM=$pc2 + uci set custom.bandlock.earfcn3$CURRMODEM=$ear3 + uci set custom.bandlock.pci3$CURRMODEM=$pc3 +fi +uci commit custom + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + + +CURRMODEM=$(uci get modem.general.miscnum) +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) +CPORT=$(uci -q get modem.modem$CURRMODEM.commport) + +ATCMDD="at+qnwlock=\"common/4g\"" +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +if `echo $OX | grep "ERROR" 1>/dev/null 2>&1` +then + ATCMDD="at+qnwlock=\"common/lte\",0" +else + ATCMDD=$ATCMDD",0" +fi +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +log "$OX" +sleep 5 +ATCMDD="AT+CFUN=1,1" +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +log "Hard modem reset done on /dev/ttyUSB$CPORT to reload drivers" +ifdown wan$CURRMODEM +uci delete network.wan$CURRMODEM +uci set network.wan$CURRMODEM=interface +uci set network.wan$CURRMODEM.proto=dhcp +uci set network.wan$CURRMODEM.${ifname1}="wan"$CURRMODEM +uci set network.wan$CURRMODEM.metric=$CURRMODEM"0" +uci commit network +/etc/init.d/network reload +ifdown wan$CURRMODEM +echo "1" > /tmp/modgone +log "Setting Modem Removal flag (1)" diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/wifiradio.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/wifiradio.sh new file mode 100644 index 0000000..1f791a0 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/luci/wifiradio.sh @@ -0,0 +1,15 @@ +#!/bin/sh +. /lib/functions.sh + +config_cb() { + local type="$1" + local name="$2" + if [ ! -z $type ]; then + if [ $type = "wifi-device" ]; then + echo $name >> /tmp/wifi-device + fi + fi +} + +rm -f /tmp/wifi-device +config_load wireless diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/mbimfind.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/mbimfind.lua new file mode 100644 index 0000000..7e7e67b --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/mbimfind.lua @@ -0,0 +1,92 @@ +#!/usr/bin/lua + +drv = {} +idV = arg[1] +idP = arg[2] + +retval = 0 +echo = 0 + +printf = function(s,...) + if pflag ~= 0 then + io.write(s:format(...)) + local ss = s:format(...) + if echo == 1 then + os.execute("/usr/lib/rooter/logprint.sh " .. ss) + end + end +end + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +-- MAIN +-- C: #Ifs= 3 Cfg#= 3 Atr=a0 MxPwr=500mA + +Cfgs = 1 +local i=0 +local file = io.open("/tmp/prembim", "r") +repeat + local line = file:read("*line") + if line == nil then + break + end + if string.len(line) > 5 then + s, e = line:find("D:") + if s ~= nil then + cs, ce = line:find("#Cfgs= ") + Cfgs = trim(line:sub(ce+1)) + --printf("Cfgs = %s\n", Cfgs) + end + + s, e = line:find("Vendor=") + if s ~= nil then + cs, ce = line:find(" ", e) + m_idV = trim(line:sub(e+1, cs-1)) + s, e = line:find("ProdID=") + cs, ce = line:find(" ", e) + m_idP = trim(line:sub(e+1, cs-1)) + --printf("%s %s\n", m_idV, m_idP) + if m_idV == idV and m_idP == idP then + if Cfgs == "1" then + break + end + Inter = 0 + repeat + line = file:read("*line") + if line == nil then + break + end + if string.len(line) > 5 then + s, e = line:find("C:") + if s ~= nil then + s, e = line:find("Cfg#= ") + cs, ce = line:find(" ", e+1) + Inter = trim(line:sub(e+1, cs)) + --printf("Inter = %s\n", Inter) + end + s, e = line:find("T:") + if s ~= nil then + break + end + s, e = line:find("Cls=02") + if s ~= nil then + s, e = line:find("Sub=0e Prot=00 Driver=") + if s ~= nil then + retval=tonumber(Inter) + --printf("retval = %d\n", retval) + break + end + end + end + until 1==0 + break + end + end + end +until 1==0 +file:close() + + +os.exit(retval) \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/modeswitch.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/modeswitch.sh new file mode 100644 index 0000000..5d9735e --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/modeswitch.sh @@ -0,0 +1,616 @@ +#!/bin/sh +. /lib/functions/procd.sh + +MODCNT=6 + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +modeswitch="/usr/bin/usb_modeswitch" + +log() { + modlog "usb-modeswitch $CURRMODEM" "$@" +} + +sanitize() { + sed -e 's/[[:space:]]\+$//; s/[[:space:]]\+/_/g' "$@" +} + +find_usb_attrs() { + local usb_dir="/sys$DEVPATH" + [ -f "$usb_dir/idVendor" ] || usb_dir="${usb_dir%/*}" + + uVid=$(cat "$usb_dir/idVendor") + uPid=$(cat "$usb_dir/idProduct") + uMa=$(sanitize "$usb_dir/manufacturer") + uPr=$(sanitize "$usb_dir/product") + uSe=$(sanitize "$usb_dir/serial") +} + +display_top() { + log "*****************************************************************" + log "*" +} + +display_bottom() { + log "*****************************************************************" +} + + +display() { + local line1=$1 + log "* $line1" + log "*" +} + +# +# Save Interface variables +# +save_variables() { + echo 'MODSTART="'"$MODSTART"'"' > /tmp/variable.file + echo 'WWAN="'"$WWAN"'"' >> /tmp/variable.file + echo 'USBN="'"$USBN"'"' >> /tmp/variable.file + echo 'ETHN="'"$ETHN"'"' >> /tmp/variable.file + echo 'WDMN="'"$WDMN"'"' >> /tmp/variable.file + echo 'BASEPORT="'"$BASEPORT"'"' >> /tmp/variable.file +} +# +# delay until ROOter Initialization done +# +bootdelay() { + if [ ! -f /tmp/bootend.file ]; then + log "Delay for boot up" + sleep 10 + while [ ! -f /tmp/bootend.file ]; do + sleep 1 + done + sleep 10 + fi +} + +# +# return modem number based on port number +# 0 is not found +# +find_device() { + DEVN=$1 + COUNTER=1 + while [ $COUNTER -le $MODCNT ]; do + EMPTY=$(uci get modem.modem$COUNTER.empty) + if [ $EMPTY -eq 0 ]; then + DEVS=$(uci get modem.modem$COUNTER.device) + if [ $DEVN = $DEVS ]; then + retresult=$COUNTER + return + fi + fi + let COUNTER=COUNTER+1 + done + retresult=0 +} + +# +# check if all modems are inactive or empty +# delete all if nothing active +# +check_all_empty() { + COUNTER=1 + while [ $COUNTER -le $MODCNT ]; do + EMPTY=$(uci get modem.modem$COUNTER.empty) + if [ $EMPTY -eq 0 ]; then + ACTIVE=$(uci get modem.modem$COUNTER.active) + if [ $ACTIVE -eq 1 ]; then + return + fi + fi + let COUNTER=COUNTER+1 + done + COUNTER=1 + while [ $COUNTER -le $MODCNT ]; do + uci delete modem.modem$COUNTER + uci set modem.modem$COUNTER=modem + uci set modem.modem$COUNTER.empty=1 + let COUNTER=COUNTER+1 + done + uci set modem.general.modemnum=1 + uci commit modem + MODSTART=1 + WWAN=0 + USBN=0 + ETHN=1 + WDMN=0 + BASEPORT=0 + if + ifconfig eth1 + then + if [ -e "/sys/class/net/eth1/device/bInterfaceProtocol" ]; then + ETHN=1 + else + ETHN=2 + fi + fi + save_variables + display_top; display "No Modems present"; display_bottom +} + +change_bconf() { + local devname=$1 + local conf=$2 + local mode=$3 + local unconf=0 + log "Switching Modem at $DEVICENAME to $mode by selecting Cfg# $bestcfg" + echo $unconf >/sys/bus/usb/devices/$devname/bConfigurationValue + sleep 1 + echo $conf >/sys/bus/usb/devices/$devname/bConfigurationValue +} + + +# +# Add Modem and connect +# +if [ "$ACTION" = add ]; then + bootdelay + CNTR=0 + while [ -e /tmp/modgone ]; do + sleep 1 + CNTR=`expr $CNTR + 1` + if [ $CNTR -gt 10 ]; then + rm -f /tmp/modgone + break + fi + done + find_usb_attrs + + if echo $DEVICENAME | grep -q ":" ; then + exit 0 + fi + + if [ -z $uMa ]; then + log "Ignoring Unnamed Hub" + exit 0 + fi + + UPR=${uPr} + CT=`echo $UPR | tr '[A-Z]' '[a-z]'` + if echo $CT | grep -q "hub" ; then + log "Ignoring Named Hub" + exit 0 + fi + + if [ $uVid = 1d6b ]; then + log "Ignoring Linux Hub" + exit 0 + fi + +# +# Ignore Ethernet adapters +# + if [ $uVid = 13b1 -a $uPid = 0041 ]; then + exit 0 + elif [ $uVid = 2357 -a $uPid = 0601 ]; then + exit 0 + elif [ $uVid = 0b95 -a $uPid = 772b ]; then + exit 0 + elif [ $uVid = 0b95 -a $uPid = 1790 ]; then + exit 0 + elif [ $uVid = 0bda -a $uPid = 8152 ]; then + exit 0 + fi + + bNumConfs=$(cat /sys/bus/usb/devices/$DEVICENAME/bNumConfigurations) + bNumIfs=$(cat /sys/bus/usb/devices/$DEVICENAME/bNumInterfaces) + + # Uncomment the next line to ignore USB-Serial adapters and similar single-port devices + # if [ $bNumConfs = 1 -a $bNumIfs = 1 ] && exit 0 + + cat /sys/kernel/debug/usb/devices > /tmp/wdrv + lua $ROOTER/protofind.lua $uVid $uPid 0 + retval=$? + + if [ -e /etc/config/mjpg-streamer ]; then + if [ $retval -eq 99 ]; then + log "Start MJPEG Streamer $DEVICENAME" + /etc/init.d/mjpg-streamer start + uci delete mjpg-streamer.camera + uci set mjpg-streamer.camera=mjpg-stream + uci set mjpg-streamer.camera.idv=$DEVICENAME + uci commit mjpg-streamer + exit 0 + fi + fi + if [ -e /etc/config/p910nd ]; then + if [ $retval -eq 98 ]; then + # Check if lp device is plugged in and p910nd is not already started + log "USB Printer device plugged in, starting p910nd" + /etc/init.d/p910nd start + uci delete p910nd.printer + uci set p910nd.printer=printer + uci set p910nd.printer.idv=$DEVICENAME + uci commit p910nd + exit 0 + fi + fi + if [ $retval -eq 97 ]; then + if grep "$uVid:$uPid" /etc/usb-mode.json > /dev/null ; then + log "Modem found" + else + log "Found USB Storage" + exit 0 + fi + fi + + DELAY=1 + if [ -f /tmp/usbwait ]; then + log "Delay for previous modem" + while [ -f /tmp/usbwait ]; do + sleep 1 + let DELAY=$DELAY+1 + if [ $DELAY -gt 15 ]; then + break + fi + done + fi + echo "1" > /tmp/usbwait + + source /tmp/variable.file + source /tmp/modcnt + MODCNT=$MODCNTX + + reinsert=0 + find_device $DEVICENAME + if [ $retresult -gt 0 ]; then + ACTIVE=$(uci get modem.modem$retresult.active) + if [ $ACTIVE = 1 ]; then + rm -f /tmp/usbwait + exit 0 + else + IDP=$(uci get modem.modem$retresult.uPid) + IDV=$(uci get modem.modem$retresult.uVid) + if [ $uVid = $IDV -a $uPid = $IDP ]; then + reinsert=1 + CURRMODEM=$retresult + MODSTART=$retresult + WWANX=$(uci get modem.modem$CURRMODEM.wwan) + if [ -n "$WWANX" ]; then + WWAN=$WWANX + save_variables + fi + WDMNX=$(uci get modem.modem$CURRMODEM.wdm) + if [ -n "$WDMNX" ]; then + WDMN=$WDMNX + save_variables + fi + else + display_top; display "Reinsert of different Modem not allowed"; display_bottom + rm -f /tmp/usbwait + exit 0 + fi + fi + fi + + log "Add : $DEVICENAME: Manufacturer=${uMa:-?} Product=${uPr:-?} Serial=${uSe:-?} $uVid $uPid" + + if [ $MODSTART -gt $MODCNT ]; then + display_top; display "Exceeded Maximun Number of Modems"; display_bottom + exit 0 + fi + + if [ $reinsert = 0 ]; then + CURRMODEM=$MODSTART + fi + + FILEN=$uVid:$uPid + display_top; display "Start of Modem Detection and Connection Information" + display "Product=${uPr:-?} $uVid $uPid"; display_bottom + cat /sys/kernel/debug/usb/devices > /tmp/prembim + lua $ROOTER/mbimfind.lua $uVid $uPid + retval=$? + rm -f /tmp/prembim + if [ ! -e /sbin/umbim ]; then + retval=0 + fi + + while : ; do + bConfig=$(cat /sys/bus/usb/devices/$DEVICENAME/bConfigurationValue) + if [ -n "$bConfig" -a -n "$bNumConfs" ]; then + log "Found Modem at $DEVICENAME in Cfg#= $bConfig from $bNumConfs available" + break + else + sleep 1 + fi + done + + FORCEQMI='03f0:0857 1bc7:1900' + if echo $FORCEQMI | grep -q -i "$FILEN"; then + bestcfg=1 + if [ $bConfig -ne $bestcfg ]; then + change_bconf $DEVICENAME $bestcfg QMI + fi + else + if [ $retval -ne 0 ]; then + display_top; display "Found MBIM Modem at $DEVICENAME with Config of $retval"; display_bottom + if [ $FILEN = "12d1:15c1" ]; then + bestcfg=2 + if [ $bConfig -ne $bestcfg ]; then + change_bconf $DEVICENAME $bestcfg ECM + fi + elif [ $FILEN = "413c:81d7" -o $FILEN = "05c6:9025" ]; then + bestcfg=1 + case $bNumConfs in + "3" ) + change_bconf $DEVICENAME $bestcfg QMI + ;; + "2" ) + if [ $bNumIfs -lt 4 ]; then + change_bconf $DEVICENAME $bestcfg QMI + fi + ;; + esac + elif [ $FILEN = "03f0:9d1d" -a $bNumConfs -eq 3 ]; then + bestcfg=1 + change_bconf $DEVICENAME $bestcfg QMI + else + if [ $bConfig -ne $retval ]; then + change_bconf $DEVICENAME $retval MBIM + fi + fi + else + if grep "$FILEN" /etc/usb-mode.json > /dev/null ; then + procd_open_service "usbmode" + procd_open_instance + procd_set_param command "/sbin/usbmode" -s + procd_close_instance + procd_close_service + else + display_top; display "Device at $DEVICENAME does not have a switch data file"; display_bottom + fi + fi + fi + sleep 10 + usb_dir="/sys$DEVPATH" + idV="$(sanitize "$usb_dir/idVendor")" + idP="$(sanitize "$usb_dir/idProduct")" + display_top; display "Modem at $DEVICENAME switched to : $idV:$idP"; display_bottom + + if [ $idV = 2357 -a $idP = 9000 ]; then + sleep 10 + fi + + cat /sys/kernel/debug/usb/devices > /tmp/wdrv + lua $ROOTER/protofind.lua $idV $idP 1 + retval=$? + if [ $idV = 8087 -a $idP = 095a ]; then + retval=28 + fi + if [ $idV = 2cb7 -a $idP = 000b ]; then + retval=28 + fi + display_top; display "ProtoFind returns : $retval"; display_bottom + rm -f /tmp/wdrv + + if [ $reinsert = 0 ]; then + BASEP=$BASEPORT + if [ -f /tmp/drv ]; then + source /tmp/drv + BASEPORT=`expr $PORTN + $BASEPORT` + fi + fi + rm -f /tmp/drv + + if [ $retval -ne 0 ]; then + log "Found Modem $CURRMODEM" + if [ $reinsert = 0 ]; then + uci set modem.modem$CURRMODEM.empty=0 + uci set modem.modem$CURRMODEM.uVid=$uVid + uci set modem.modem$CURRMODEM.uPid=$uPid + uci set modem.modem$CURRMODEM.idV=$idV + uci set modem.modem$CURRMODEM.idP=$idP + uci set modem.modem$CURRMODEM.device=$DEVICENAME + uci set modem.modem$CURRMODEM.baseport=$BASEP + uci set modem.modem$CURRMODEM.maxport=$BASEPORT + uci set modem.modem$CURRMODEM.proto=$retval + uci set modem.modem$CURRMODEM.maxcontrol=/sys$DEVPATH/descriptors + find_usb_attrs + uci set modem.modem$CURRMODEM.manuf=$uMa + uci set modem.modem$CURRMODEM.model=$uPr + uci set modem.modem$CURRMODEM.serial=$uSe + uci set modem.modem$CURRMODEM.celltype="-" + fi + uci set modem.modem$CURRMODEM.active=1 + uci set modem.modem$CURRMODEM.connected=0 + uci commit modem + if [ -e $ROOTER/modem-led.sh ]; then + $ROOTER/modem-led.sh $CURRMODEM 1 + fi + fi + + if [ $reinsert = 0 -a $retval != 0 ]; then + MODSTART=`expr $MODSTART + 1` + save_variables + fi + +# +# Handle specific modem models +# + case $retval in + "0" ) + # + # ubox GPS module + # + if [ $idV = 1546 ]; then + if echo $uPr | grep -q "GPS"; then + SYMLINK="gps0" + BASEX=`expr 1 + $BASEP` + ln -s /dev/ttyUSB$BASEX /dev/${SYMLINK} + display_top ; display "Hotplug Symlink from /dev/ttyUSB$BASEX to /dev/${SYMLINK} created" + display_bottom + fi + fi + rm -f /tmp/usbwait + exit 0 + ;; + "1" ) + log "Connecting a Sierra Modem" + ln -s $ROOTER/connect/create_connect.sh $ROOTER_LINK/create_proto$CURRMODEM + $ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM & + ;; + "2" ) + log "Connecting a QMI Modem" + ln -s $ROOTER/connect/create_connect.sh $ROOTER_LINK/create_proto$CURRMODEM + $ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM & + ;; + "88" ) + log "Connecting a Quectel Rmnet Modem" + ln -s $ROOTER/connect/create_connect.sh $ROOTER_LINK/create_proto$CURRMODEM + $ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM & + ;; + + "3" ) + log "Connecting a MBIM Modem" + ln -s $ROOTER/connect/create_connect.sh $ROOTER_LINK/create_proto$CURRMODEM + $ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM & + ;; + "6"|"4"|"7"|"24"|"26"|"27" ) + log "Connecting a Huawei NCM Modem" + ln -s $ROOTER/connect/create_connect.sh $ROOTER_LINK/create_proto$CURRMODEM + $ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM & + ;; + "28" ) + log "Connecting a Fibocom NCM Modem" + ln -s $ROOTER/connect/create_connect.sh $ROOTER_LINK/create_proto$CURRMODEM + $ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM & + ;; + "5" ) + log "Connecting a Hostless Modem or Phone" + ln -s $ROOTER/connect/create_hostless.sh $ROOTER_LINK/create_proto$CURRMODEM + $ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM & + ;; + "10"|"11"|"12"|"13"|"14"|"15"|"16" ) + log "Connecting a PPP Modem" + ln -s $ROOTER/ppp/create_ppp.sh $ROOTER_LINK/create_proto$CURRMODEM + $ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM + ;; + "9" ) + log "Connecting an iPhone" + ln -s $ROOTER/connect/create_iphone.sh $ROOTER_LINK/create_proto$CURRMODEM + $ROOTER_LINK/create_proto$CURRMODEM $CURRMODEM + ;; + esac + +fi + +# +# Remove Modem +# +if [ "$ACTION" = remove ]; then + find_usb_attrs + + if echo $DEVICENAME | grep -q ":" ; then + exit 0 + fi + find_device $DEVICENAME + if [ $retresult -gt 0 ]; then + IDP=$(uci get modem.modem$retresult.idP) + IDV=$(uci get modem.modem$retresult.idV) + if [ $uVid = $IDV ]; then + exit 0 + else + INTER=$(uci get modem.modem$retresult.inter) + if [ -z $INTER ]; then + INTER=$retresult + fi + if [ -e $ROOTER/modem-led.sh ]; then + $ROOTER/modem-led.sh $retresult 0 + fi + uci set modem.modem$retresult.active=0 + uci set modem.modem$retresult.connected=0 + uci commit modem + if [ -e /etc/config/mwan3 ]; then + ENB=$(uci get mwan3.wan$retresult.enabled) + if [ ! -z $ENB ]; then + uci set mwan3.wan$INTER.enabled=0 + uci commit mwan3 + fi + fi + SMS=$(uci get modem.modem$CURRMODEM.sms) + if [ $SMS = 1 ]; then + if [ -e /usr/lib/sms/stopsms ]; then + /usr/lib/sms/stopsms $CURRMODEM + fi + fi + ifdown wan$INTER + uci delete network.wan$INTER + uci set network.wan$INTER=interface + uci set network.wan$INTER.proto=dhcp + ifname1="ifname" + if [ -e /etc/newstyle ]; then + ifname1="device" + fi + uci set network.wan$INTER.${ifname1}=" " + uci set network.wan$INTER.metric=$INTER"0" + uci commit network + /etc/init.d/network reload + ifdown wan$INTER + PID=$(ps |grep "getsignal$retresult" | grep -v grep |head -n 1 | awk '{print $1}') + kill -9 $PID + rm -f $ROOTER_LINK/getsignal$retresult + PID=$(ps |grep "reconnect$retresult" | grep -v grep |head -n 1 | awk '{print $1}') + kill -9 $PID + rm -f $ROOTER_LINK/reconnect$retresult + PID=$(ps |grep "create_proto$retresult" | grep -v grep |head -n 1 | awk '{print $1}') + kill -9 $PID + rm -f $ROOTER_LINK/create_proto$retresult + PID=$(ps |grep "processsms$retresult" | grep -v grep |head -n 1 | awk '{print $1}') + kill -9 $PID + rm -f $ROOTER_LINK/processsms$retresult + PID=$(ps |grep "con_monitor$retresult" | grep -v grep |head -n 1 | awk '{print $1}') + kill -9 $PID + rm -f $ROOTER_LINK/con_monitor$retresult + PID=$(ps |grep "mbim_monitor$retresult" | grep -v grep |head -n 1 | awk '{print $1}') + kill -9 $PID + rm -f $ROOTER_LINK/mbim_monitor$retresult + if [ -e /usr/lib/gps/gpskill.sh ]; then + /usr/lib/gps/gpskill.sh $retresult + fi + $ROOTER/signal/status.sh $retresult "No Modem Present" + $ROOTER/log/logger "Disconnect (Removed) Modem #$retresult" + display_top; display "Remove : $DEVICENAME : Modem $retresult"; display_bottom + check_all_empty + rm -f /tmp/usbwait + rm -f /tmp/mdown$retresult + rm -f /tmp/msimdata$retresult + rm -f /tmp/msimnum$retresult + rm -f /tmp/modgone + rm -f /tmp/bmask + rm -f /tmp/simpin$retresult + fi + else + IDV=$(uci get mjpg-streamer.camera.idv) + if [ ! -z $IDV ]; then + if [ $DEVICENAME = $IDV ]; then + uci delete mjpg-streamer.camera + uci commit mjpg-streamer + /etc/init.d/mjpg-streamer stop + log "Stop MJPEG-Streamer" + fi + fi + IDV=$(uci get p910nd.printer.idv) + if [ ! -z $IDV ]; then + if [ $DEVICENAME = $IDV ]; then + uci delete p910nd.printer + uci commit p910nd + if [ ! -d /sys$DEVPATH/*/lp0 -a -f /var/run/p9100d.pid ]; then + log "USB Printer device unplugged, stopping p910nd" + /etc/init.d/p910nd stop + # p910nd does not seem to remove .pid file when stopped, removing it manually + rm /var/run/p9100d.pid + fi + fi + fi + fi +fi + +if [ "$ACTION" = "motion" ]; then + logger webcam motion event +fi + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/ncmfind.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/ncmfind.lua new file mode 100644 index 0000000..3e39cb3 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/ncmfind.lua @@ -0,0 +1,63 @@ +#!/usr/bin/lua + +drv = {} +idV = arg[1] +idP = arg[2] + +printf = function(s,...) + io.write(s:format(...)) +end + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +local Inter=0 +local file = io.open("/tmp/wdrv", "r") +repeat + local line = file:read("*line") + if line == nil then + break + end + if string.len(line) > 5 then + s, e = line:find("Vendor=") + if s ~= nil then + cs, ce = line:find(" ", e) + m_idV = trim(line:sub(e+1, cs-1)) + s, e = line:find("ProdID=") + cs, ce = line:find(" ", e) + m_idP = trim(line:sub(e+1, cs-1)) + if m_idV == idV and m_idP == idP then + repeat + line = file:read("*line") + if line == nil then + break + end + if string.len(line) > 5 then + s, e = line:find("Prot=") + if s ~= nil then + cs, ce = line:find(" ", e+1) + proto = trim(line:sub(e+1, cs)) + if proto == "2" or proto == "02" or proto == "12" or proto == "32" or proto == "42" or proto == "62" or proto == "72" then + break + else + s, e = line:find("=option") + if s ~= nil then + Inter = Inter + 1 + end + end + end + s, e = line:find("T:") + if s ~= nil then + break + end + end + until 1==0 + break + end + end + end +until 1==0 +file:close() + +os.exit(Inter) \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/nitz2sys.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/nitz2sys.sh new file mode 100644 index 0000000..1a00770 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/nitz2sys.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +log() { + logger -t "NITZ set time" "$@" +} + +CURRMODEM=$(uci -q get modem.general.modemnum) +COMMPORT="/dev/ttyUSB"$(uci -q get modem.modem$CURRMODEM.commport) +ROOTER=/usr/lib/rooter + +ATCMDD="AT+CTZU?;+CCLK?" +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +OX=$OX +SUCCESS=1 +NITZstat=$(echo "$OX" | grep "+CTZU: 1") +if [ -n "$NITZstat" ]; then + DTG=$(echo "$OX" | grep -o "+CCLK:.*" | cut -d\" -f2) + DTGyymmdd=$(echo "$DTG" | cut -d, -f1 | tr '/' '-') + DTGhhmmss=$(echo "$DTG" | cut -d, -f2) + DTGhhmmss=${DTGhhmmss:0:8} + DTGtz=$(echo "$DTG" | grep -o "[-+][0-9]\{1,2\}") + if [ -n "$DTGtz" ]; then + DTGif=$(date +%s -u -s "$DTGyymmdd $DTGhhmmss") + OX=$(date -s @$DTGif) + log "$OX" + SUCCESS=0 + fi +fi +exit $SUCCESS diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/portchge.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/portchge.sh new file mode 100644 index 0000000..968f039 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/portchge.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +DIR=$1 + +log() { + logger -t "port change" "$@" +} + + +CURRMODEM=$(uci get modem.general.modemnum) +BASEP=$(uci get modem.modem$CURRMODEM.baseport) +MAXP=$(uci get modem.modem$CURRMODEM.maxport) +PORT=$(uci get modem.modem$CURRMODEM.commport) + +log "$DIR" + +if [ $DIR = "up" ]; then + if [ $PORT -lt $MAXP ]; then + PORT=`expr $PORT + 1` + echo 'PORT="'"$PORT"'"' > /tmp/port$CURRMODEM.file + fi +else + if [ $PORT -gt $BASEP ]; then + PORT=`expr $PORT - 1` + echo 'PORT="'"$PORT"'"' > /tmp/port$CURRMODEM.file + fi +fi + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/ppp/create_ppp.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/ppp/create_ppp.sh new file mode 100644 index 0000000..e018901 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/ppp/create_ppp.sh @@ -0,0 +1,247 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "Create Connection $CURRMODEM" "$@" +} + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + +set_dns() { + local pDNS1=$(uci -q get modem.modeminfo$CURRMODEM.dns1) + local pDNS2=$(uci -q get modem.modeminfo$CURRMODEM.dns2) + local pDNS3=$(uci -q get modem.modeminfo$CURRMODEM.dns3) + local pDNS4=$(uci -q get modem.modeminfo$CURRMODEM.dns4) + + local aDNS="$pDNS1 $pDNS2 $pDNS3 $pDNS4" + local bDNS="" + + echo "$aDNS" | grep -o "[[:graph:]]" &>/dev/null + if [ $? = 0 ]; then + log "Using DNS settings from the Connection Profile" + pdns=1 + for DNSV in $(echo "$aDNS"); do + if [ "$DNSV" != "0.0.0.0" ] && [ -z "$(echo "$bDNS" | grep -o "$DNSV")" ]; then + [ -n "$(echo "$DNSV" | grep -o ":")" ] && continue + bDNS="$bDNS $DNSV" + fi + done + + bDNS=$(echo $bDNS) + if [ $DHCP = 1 ]; then + uci set network.wan$INTER.peerdns=0 + uci set network.wan$INTER.dns="$bDNS" + fi + echo "$bDNS" > /tmp/v4dns$INTER + + bDNS="" + for DNSV in $(echo "$aDNS"); do + if [ "$DNSV" != "0:0:0:0:0:0:0:0" ] && [ -z "$(echo "$bDNS" | grep -o "$DNSV")" ]; then + [ -z "$(echo "$DNSV" | grep -o ":")" ] && continue + bDNS="$bDNS $DNSV" + fi + done + echo "$bDNS" > /tmp/v6dns$INTER + else + log "Using Provider assigned DNS" + pdns=0 + rm -f /tmp/v[46]dns$INTER + fi +} + +save_variables() { + echo 'MODSTART="'"$MODSTART"'"' > /tmp/variable.file + echo 'WWAN="'"$WWAN"'"' >> /tmp/variable.file + echo 'USBN="'"$USBN"'"' >> /tmp/variable.file + echo 'ETHN="'"$ETHN"'"' >> /tmp/variable.file + echo 'WDMN="'"$WDMN"'"' >> /tmp/variable.file + echo 'BASEPORT="'"$BASEPORT"'"' >> /tmp/variable.file +} + +get_connect() { + NAPN=$(uci get modem.modeminfo$CURRMODEM.apn) + NUSER=$(uci get modem.modeminfo$CURRMODEM.user) + NPASS=$(uci get modem.modeminfo$CURRMODEM.passw) + NAUTH=$(uci get modem.modeminfo$CURRMODEM.auth) + PINC=$(uci get modem.modeminfo$CURRMODEM.pincode) + + uci set modem.modem$CURRMODEM.apn=$NAPN + uci set modem.modem$CURRMODEM.user=$NUSER + uci set modem.modem$CURRMODEM.pass=$NPASS + uci set modem.modem$CURRMODEM.auth=$NAUTH + uci set modem.modem$CURRMODEM.pin=$PINC + uci commit modem +} + +CURRMODEM=$1 +source /tmp/variable.file + +MAN=$(uci get modem.modem$CURRMODEM.manuf) +MOD=$(uci get modem.modem$CURRMODEM.model) +BASEP=$(uci get modem.modem$CURRMODEM.baseport) +$ROOTER/signal/status.sh $CURRMODEM "$MAN $MOD" "Connecting" +PROT=$(uci get modem.modem$CURRMODEM.proto) + +DELAY=$(uci get modem.modem$CURRMODEM.delay) +if [ -z $DELAY ]; then + DELAY=5 +fi + +idV=$(uci get modem.modem$CURRMODEM.idV) +idP=$(uci get modem.modem$CURRMODEM.idP) + +cat /sys/kernel/debug/usb/devices > /tmp/cdma +lua $ROOTER/cdmafind.lua $idV $idP +retval=$? +rm -f /tmp/cdma +if [ $retval -eq 1 ]; then + log "Found CDMA modem" +fi + +case $PROT in +"10" ) + if [ $retval -eq 0 ]; then + DP=0 + CP=2 + else + DP=0 + CP=0 + fi + ;; +"11"|"12" ) + if [ $retval -eq 0 ]; then + DP=2 + CP=1 + else + DP=0 + CP=0 + fi + ;; +"13" ) + if [ $retval -eq 0 ]; then + DP=4 + CP=3 + else + DP=0 + CP=0 + fi + ;; +"14" ) + if [ $retval -eq 0 ]; then + DP=3 + CP=2 + else + DP=0 + CP=0 + fi + ;; +"15" ) + if [ $retval -eq 0 ]; then + DP=1 + CP=2 + else + DP=0 + CP=0 + fi + ;; +"16" ) + if [ $retval -eq 0 ]; then + DP=2 + CP=0 + ln -s /dev/ttyACM$CP /dev/ttyUSB$CP + ln -s /dev/ttyACM$DP /dev/ttyUSB$DP + else + DP=0 + CP=0 + fi + ;; +esac +$ROOTER/common/modemchk.lua "$idV" "$idP" "$DP" "$CP" +source /tmp/parmpass + +CPORT=`expr $CPORT + $BASEP` +DPORT=`expr $DPORT + $BASEP` +uci set modem.modem$CURRMODEM.commport=$CPORT +uci set modem.modem$CURRMODEM.dataport=$DPORT +uci set modem.modem$CURRMODEM.service=$retval +uci commit modem + +$ROOTER/common/gettype.sh $CURRMODEM +$ROOTER/connect/get_profile.sh $CURRMODEM +get_connect + +INTER=$(uci get modem.modeminfo$CURRMODEM.inter) +if [ -z $INTER ]; then + INTER=$CURRMODEM +else + if [ $INTER = 0 ]; then + INTER=$CURRMODEM + fi +fi +log "Profile for Modem $CURRMODEM sets interface to WAN$INTER" +OTHER=1 +if [ $CURRMODEM = 1 ]; then + OTHER=2 +fi +EMPTY=$(uci get modem.modem$OTHER.empty) +if [ $EMPTY = 0 ]; then + OINTER=$(uci get modem.modem$OTHER.inter) + if [ ! -z $OINTER ]; then + if [ $INTER = $OINTER ]; then + INTER=1 + if [ $OINTER = 1 ]; then + INTER=2 + fi + log "Switched Modem $CURRMODEM to WAN$INTER as Modem $OTHER is using WAN$OINTER" + fi + fi +fi +uci set modem.modem$CURRMODEM.inter=$INTER +uci commit modem +log "Modem $CURRMODEM is using WAN$INTER" +uci delete network.wan$INTER +uci set network.wan$INTER=interface +uci set network.wan$INTER.${ifname1}=3x-wan$INTER +uci set network.wan$INTER.proto=3x +if [ $retval -eq 0 ]; then + uci set network.wan$INTER.service=umts +else + uci set network.wan$INTER.service=cdma +fi +uci set network.wan$INTER.keepalive=10 +uci set network.wan$INTER.device=/dev/ttyUSB$DPORT +uci set network.wan$INTER.apn=$NAPN +uci set network.wan$INTER.username=$NUSER +uci set network.wan$INTER.auth=$NAUTH +uci set network.wan$INTER.password=$NPASS +uci set network.wan$INTER.pincode=$PINC +uci set network.wan$INTER.metric=$CURRMODEM"0" +uci set network.wan$INTER.currmodem=$CURRMODEM +uci set network.wan$INTER.pppd_options="debug noipdefault" +set_dns +uci commit network + +log "PPP Comm Port : /dev/ttyUSB$CPORT" +log "PPP Data Port : /dev/ttyUSB$DPORT" + +if [ $retval -eq 0 ]; then + case $idV in + "1199"|"0f3d"|"413c"|"2c7c"|"05c6" ) + $ROOTER/luci/celltype.sh $CURRMODEM + ;; + esac + $ROOTER/common/lockchk.sh $CURRMODEM + $ROOTER/sms/check_sms.sh $CURRMODEM & +fi + +if [ -e $ROOTER/modem-led.sh ]; then + $ROOTER/modem-led.sh $CURRMODEM 2 +fi + +rm -f /tmp/usbwait +ifup wan$INTER diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/protofind.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/protofind.lua new file mode 100644 index 0000000..03f9b47 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/protofind.lua @@ -0,0 +1,254 @@ +#!/usr/bin/lua + +drv = {} +idV = arg[1] +idP = arg[2] +pflag = arg[3] +if pflag == nil then + pflag = 1 +end + +special = {} +-- PPP special cases +-- VID PID port # +special[1] = "1bbb" ; special[2] = "0017" ; special[3] = 13 +special[4] = "12d1" ; special[5] = nil ; special[6] = 10 +special[7] = "1546" ; special[8] = "01a6" ; special[9] = 0 +special[10] = "1546" ; special[11] = "01a5" ; special[12] = 0 +special[13] = "1199" ; special[14] = "68a3" ; special[15] = 14 +special[16] = "2001" ; special[17] = "7e35" ; special[18] = 15 + + +retval = 0 +echo = 1 + +printf = function(s,...) + if pflag ~= 0 then + io.write(s:format(...)) + local ss = s:format(...) + if echo == 1 then + os.execute("/usr/lib/rooter/logprint.sh " .. ss) + end + end +end + +function trim(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end + +function checkserial() + local got = 0 + j = 1 + repeat + if drv[j] ~= nil then + if drv[j] == "option" or drv[j] == "qcserial" or drv[j] == "usb_serial" or drv[j] == "sierra" then + got = 1 + break + end + j = j + 1 + end + until drv[j] == nil + return got +end + +function countserial() + local got = 0 + j = 1 + repeat + if drv[j] ~= nil then + if drv[j] == "option" or drv[j] == "sierra" or drv[j] == "usb_serial" or drv[j] == "qcserial" then + got = got + 1 + end + j = j + 1 + end + until drv[j] == nil + return got +end + +-- MAIN + +local t = {} + +local i=0 +local file = io.open("/tmp/wdrv", "r") +repeat + local line = file:read("*line") + if line == nil then + break + end + if string.len(line) > 5 then + s, e = line:find("Vendor=") + if s ~= nil then + cs, ce = line:find(" ", e) + m_idV = trim(line:sub(e+1, cs-1)) + s, e = line:find("ProdID=") + cs, ce = line:find(" ", e) + m_idP = trim(line:sub(e+1, cs-1)) + if m_idV == idV and m_idP == idP then + repeat + line = file:read("*line") + if line == nil then + break + end + if string.len(line) > 5 then + s, e = line:find("T:") + if s ~= nil then + break + end + s, e = line:find("Cls=02") + if s ~= nil then + t[i] = trim(line:sub(63)) + i = i + 1 + end + s, e = line:find("Cls=ff") + if s ~= nil then + t[i] = trim(line:sub(63)) + i = i + 1 + end + s, e = line:find("1 Cls=e0") + if s ~= nil then + t[i] = trim(line:sub(63)) + i = i + 1 + end + s, e = line:find("Cls=0a") + if s ~= nil then + t[i] = trim(line:sub(63)) + i = i + 1 + end + s, e = line:find("Cls=0e") + if s ~= nil then + t[i] = trim(line:sub(63)) + i = i + 1 + end + s, e = line:find("Cls=07") + if s ~= nil then + t[i] = trim(line:sub(63)) + i = i + 1 + end + s, e = line:find("Cls=08") + if s ~= nil then + t[i] = trim(line:sub(63)) + i = i + 1 + end + end + until 1==0 + break + end + end + end +until 1==0 +file:close() +if i > 0 then + file = io.open("/tmp/drv", "w") + for j=0,i-1 do + drv[j+1] = t[j] + drver = string.format("%s%d%s%q", "DRIVER", j+1, "=", t[j]) + file:write(drver .. "\n") + end + ports = countserial() + drver = string.format("%s%s%d%s", "PORTN", "=\"", ports, "\"") + file:write(drver .. "\n") + file:close() +end + +i = 1 +repeat + if drv[i] ~= nil then + printf("Driver Name : %d %s\n", i, drv[i]) + i = i + 1 + end +until drv[i] == nil + +i = 1 +repeat + if drv[i] ~= nil then + if drv[i] == "sierra_net" then + retval = 1 + break + end + if drv[i] == "qmi_wwan" then + retval = 2 + break + end + + if drv[i] == "qmi_wwan_q" then + retval = 88 + break + end + + if drv[i] == "cdc_mbim" then + retval = 3 + break + end + if drv[i] == "huawei_cdc_ncm" then + if i == 2 then + retval = 4 + else + if i == 3 then + retval = 6 + else + retval = 7 + end + end + break + end + if drv[i] == "cdc_ncm" then + if i == 2 then + retval = 24 + else + if i == 3 then + retval = 26 + else + retval = 27 + end + end + break + end + if drv[i] == "cdc_ether" or drv[i] == "rndis_host" then + retval = 5 + break + end + if drv[i] == "ipheth" then + retval = 9 + break + end + if drv[i] == "uvcvideo" then + retval = 99 + break + end + if drv[i] == "usblp" then + retval = 98 + break + end + if drv[i] == "usb-storage" then + retval = 97 + end + i = i + 1 + end +until drv[i] == nil + +if retval == 0 then + if checkserial() == 1 then + retval = 88 + k = 1 + vendor = special[k] + while vendor ~= nil do + if idV == vendor then + if special[k+1] == nil then + retval = special[k+2] + break + else + if special[k+1] == idP then + retval = special[k+2] + break + end + end + end + k = k + 3 + vendor = special[k] + end + end +end + +os.exit(retval) + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/pwrtoggle.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/pwrtoggle.sh new file mode 100644 index 0000000..aaa15c7 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/pwrtoggle.sh @@ -0,0 +1,181 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + modlog "Power Toggle $CURRMODEM" "$@" +} + +ifname1="ifname" +if [ -e /etc/newstyle ]; then + ifname1="device" +fi + +waitfor() { + CNTR=0 + while [ -e /tmp/modgone ]; do + sleep 1 + CNTR=`expr $CNTR + 1` + if [ $CNTR -gt 35 ]; then + rm -f /tmp/modgone + break + fi + done +} + +rebind() { + CFUNDONE=false + ARG=$1 + CURRMODEM=$(echo "${ARG: -1}") + PROT=$(uci -q get modem.modem$CURRMODEM.proto) + CPORT=$(uci -q get modem.modem$CURRMODEM.commport) + if [ -n "$CPORT" ]; then + VENDOR=$(uci -q get modem.modem$CURRMODEM.idV) + PRODUCT=$(uci -q get modem.modem$CURRMODEM.idP) + # list vendors that do not fully support 3GPP +CFUN + NOCFUN="2c7c" # Quectel will stuck after CFUN, so not using that method at all + case $VENDOR in + "12d1" ) + ATCMDD="AT^RESET" + ;; + "2c7c" ) + ATCMDD="AT" + ;; + * ) + ATCMDD="AT+CFUN=1,1" + ;; + esac + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + if `echo ${OX} | grep "OK" 1>/dev/null 2>&1` && \ + [[ ! `echo $NOCFUN | grep -o "$VENDOR"` ]]; then + CFUNDONE=true + log "Hard modem reset done on /dev/ttyUSB$CPORT to reload drivers" + ifdown wan$CURRMODEM + uci delete network.wan$CURRMODEM + uci set network.wan$CURRMODEM=interface + uci set network.wan$CURRMODEM.proto=dhcp + uci set network.wan$CURRMODEM.${ifname1}="wan"$CURRMODEM + uci set network.wan$CURRMODEM.metric=$CURRMODEM"0" + uci commit network + /etc/init.d/network reload + ifdown wan$CURRMODEM + echo "1" > /tmp/modgone + log "Setting Modem Removal flag (1)" + fi + fi + if ! $CFUNDONE; then + PORT=$1 + log "Re-binding USB driver on $PORT to reset modem" + echo $PORT > /sys/bus/usb/drivers/usb/unbind + sleep 35 + echo $PORT > /sys/bus/usb/drivers/usb/bind + ifdown wan$CURRMODEM + uci delete network.wan$CURRMODEM + uci set network.wan$CURRMODEM=interface + uci set network.wan$CURRMODEM.proto=dhcp + uci set network.wan$CURRMODEM.${ifname1}="wan"$CURRMODEM + uci set network.wan$CURRMODEM.metric=$CURRMODEM"0" + uci commit network + /etc/init.d/network reload + ifdown wan$CURRMODEM + echo "1" > /tmp/modgone + log "Setting Modem Removal flag (2)" + if [[ -n "$CPORT" ]] && [[ ! `echo $NOCFUN | grep -o "$VENDOR"` ]]; then + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + sleep 30 + else + if [ -f $ROOTER_LINK/reconnect$CURRMODEM ]; then + $ROOTER_LINK/reconnect$CURRMODEM $CURRMODEM & + fi + fi + fi +} + +power_toggle() { + MODE=$1 + REBIND=false + if [ -f "/tmp/gpiopin" ]; then + rm -f /tmp/modgone + source /tmp/gpiopin + if [ -f "/tmp/gpioname" ]; then + source /tmp/gpioname + else + echo "$GPIOPIN" > /sys/class/gpio/unexport + echo "$GPIOPIN" > /sys/class/gpio/export + if [ $? -eq 0 ]; then + echo "out" > /sys/class/gpio/gpio$GPIOPIN/direction + if [ $? -ne 0 ]; then + REBIND=true + fi + else + REBIND=true + fi + fi + if ! $REBIND; then + if [ -z $GPIOPIN2 ]; then + if [ -z $GPIONAME ]; then + GPIOT="gpio$GPIOPIN" + else + GPIOT=$GPIONAME + fi + echo 0 > /sys/class/gpio/$GPIOT/value + waitfor + echo 1 > /sys/class/gpio/$GPIOT/value + else + if [ -z $GPIONAME2 ]; then + echo "$GPIOPIN2" > /sys/class/gpio/unexport + echo "$GPIOPIN2" > /sys/class/gpio/export + echo "out" > /sys/class/gpio/gpio$GPIOPIN2/direction + + GPIOT2="gpio$GPIOPIN2" + else + GPIOT2=$GPIONAME2 + fi + if [ -z $GPIONAME ]; then + GPIOT="gpio$GPIOPIN" + else + GPIOT=$GPIONAME + fi + if [ $MODE = 1 ]; then + echo 0 > /sys/class/gpio/$GPIOT/value + waitfor + echo 1 > /sys/class/gpio/$GPIOT/value + fi + if [ $MODE = 2 ]; then + echo 0 > /sys/class/gpio/$GPIOT2/value + waitfor + echo 1 > /sys/class/gpio/$GPIOT2/value + fi + if [ $MODE = 3 ]; then + echo 0 > /sys/class/gpio/$GPIOT/value + echo 0 > /sys/class/gpio/$GPIOT2/value + waitfor + echo 1 > /sys/class/gpio/$GPIOT/value + echo 1 > /sys/class/gpio/$GPIOT2/value + fi + sleep 2 + fi + echo "1" > /tmp/modgone + log "Power Toggle Modem" + log "Setting Modem Removal flag (3)" + fi + else + REBIND=true + fi + if $REBIND; then + # unbind/bind driver from USB to reset modem when power toggle is selected, but not available + if [ $MODE = 1 ]; then + PORT="usb1" + rebind $PORT + fi + if [ $MODE = 2 ]; then + PORT="usb2" + rebind $PORT + fi + echo "1" > /tmp/modgone + log "Setting Modem Removal flag (4)" + fi +} + +power_toggle $1 diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/shutall.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/shutall.sh new file mode 100644 index 0000000..32aabd9 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/shutall.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +CURRMODEM=1 +COMMPORT=$(uci get modem.modem$CURRMODEM.commport) +if [ -n "$COMMPORT" ]; then + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+CFUN=0") +fi +CURRMODEM=2 +COMMPORT=$(uci get modem.modem$CURRMODEM.commport) +if [ -n "$COMMPORT" ]; then + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$COMMPORT" "run-at.gcom" "$CURRMODEM" "AT+CFUN=0") +fi +poweroff diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/basedata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/basedata.sh new file mode 100644 index 0000000..6357516 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/basedata.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "basedata" "$@" +} + +CURRMODEM=$1 +COMMPORT=$2 + +get_base() { + echo "0" > /tmp/block + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "baseinfo.gcom" "$CURRMODEM") + O=$($ROOTER/common/processat.sh "$OX") + rm -f /tmp/block +} + +get_base + +DOWN=$(echo "$O" | awk -F[,] '/\+CGEQNEG:/ {printf "%s", $4}') +if [ "x$DOWN" != "x" ]; then + UP=$(echo "$O" | awk -F[,] '/\+CGEQNEG:/ {printf "%s", $3}') + DOWN=$DOWN" kbps Down | " + UP=$UP" kbps Up" +else + DOWN="-" + UP="-" +fi + +MANUF=$(echo "$O" | awk -F[:] '/Manufacturer:/ { print $2}') +if [ "x$MANUF" = "x" ]; then + MANUF=$(uci get modem.modem$CURRMODEM.manuf) +fi + +MODEL=$(echo "$O" | awk -F[,\ ] '/^\+MODEL:/ {print $2}') +if [ "x$MODEL" != "x" ]; then + MODEL=$(echo "$MODEL" | sed -e 's/"//g') + if [ $MODEL = 0 ]; then + MODEL = "mf820" + fi +else + MODEL=$(uci get modem.modem$CURRMODEM.model) +fi +MODEM=$MANUF" "$MODEL + +pval=$(uci get modem.modem$CURRMODEM.proto) +case $pval in +"1" ) + PROTO="Direct-IP" + ;; +"2" ) + PROTO="QMI" + ;; +"88" ) + PROTO="QUECTEL RMNET" + ;; +"3"|"30" ) + PROTO="MBIM" + ;; +"6"|"4"|"7"|"24"|"26"|"27"|"28" ) + PROTO="NCM" + ;; +"10"|"11"|"12"|"13"|"14"|"15" ) + PROTO="PPP" + ;; +"5" ) + PROTO="Ethernet" + ;; +"9" ) + PROTO="ipheth" + ;; +esac + +echo 'MODEM="'"$MODEM"'"' >> /tmp/base$CURRMODEM.file +echo 'DOWN="'"$DOWN"'"' >> /tmp/base$CURRMODEM.file +echo 'UP="'"$UP"'"' >> /tmp/base$CURRMODEM.file +echo 'PROTO="'"$PROTO"'"' >> /tmp/base$CURRMODEM.file + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/celldata.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/celldata.sh new file mode 100644 index 0000000..4e163f7 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/celldata.sh @@ -0,0 +1,136 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +CURRMODEM=$1 +COMMPORT=$2 + +if [ -e /etc/nocops ]; then + echo "0" > /tmp/block + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "cellinfo0.gcom" "$CURRMODEM") + rm -f /tmp/block +else + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "cellinfo0.gcom" "$CURRMODEM") +fi +OY=$($ROOTER/gcom/gcom-locked "$COMMPORT" "cellinfo.gcom" "$CURRMODEM") +OXx=$OX + +OX=$(echo $OX | tr 'a-z' 'A-Z') +OY=$(echo $OY | tr 'a-z' 'A-Z') +OX=$OX" "$OY + +COPS="-" +COPS_MCC="-" +COPS_MNC="-" +COPSX=$(echo $OXx | grep -o "+COPS: [01],0,.\+," | cut -d, -f3 | grep -o "[^\"]\+") + +if [ "x$COPSX" != "x" ]; then + COPS=$COPSX +fi + +COPSX=$(echo $OX | grep -o "+COPS: [01],2,.\+," | cut -d, -f3 | grep -o "[^\"]\+") + +if [ "x$COPSX" != "x" ]; then + COPS_MCC=${COPSX:0:3} + COPS_MNC=${COPSX:3:3} + if [ "$COPS" = "-" ]; then + COPS=$(awk -F[\;] '/'$COPS'/ {print $2}' $ROOTER/signal/mccmnc.data) + [ "x$COPS" = "x" ] && COPS="-" + fi +fi + +if [ "$COPS" = "-" ]; then + COPS=$(echo "$O" | awk -F[\"] '/^\+COPS: 0,0/ {print $2}') + if [ "x$COPS" = "x" ]; then + COPS="-" + COPS_MCC="-" + COPS_MNC="-" + fi +fi +COPS_MNC=" "$COPS_MNC + +OX=$(echo "${OX//[ \"]/}") + +CID="" +CID5="" +RAT="" +REGV=$(echo "$OX" | grep -o "+C5GREG:2,[0-9],[A-F0-9]\{2,6\},[A-F0-9]\{5,10\},[0-9]\{1,2\}") +if [ -n "$REGV" ]; then + LAC5=$(echo "$REGV" | cut -d, -f3) + LAC5=$LAC5" ($(printf "%d" 0x$LAC5))" + CID5=$(echo "$REGV" | cut -d, -f4) + CID5L=$(printf "%010X" 0x$CID5) + RNC5=${CID5L:1:6} + RNC5=$RNC5" ($(printf "%d" 0x$RNC5))" + CID5=${CID5L:7:3} + CID5="Short $(printf "%X" 0x$CID5) ($(printf "%d" 0x$CID5)), Long $(printf "%X" 0x$CID5L) ($(printf "%d" 0x$CID5L))" + RAT=$(echo "$REGV" | cut -d, -f5) +fi +REGV=$(echo "$OX" | grep -o "+CEREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{5,8\}") +REGFMT="3GPP" +if [ -z "$REGV" ]; then + REGV=$(echo "$OX" | grep -o "+CEREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{1,3\},[A-F0-9]\{5,8\}") + REGFMT="SW" +fi +if [ -n "$REGV" ]; then + LAC=$(echo "$REGV" | cut -d, -f3) + LAC=$(printf "%04X" 0x$LAC)" ($(printf "%d" 0x$LAC))" + if [ $REGFMT = "3GPP" ]; then + CID=$(echo "$REGV" | cut -d, -f4) + else + CID=$(echo "$REGV" | cut -d, -f5) + fi + CIDL=$(printf "%08X" 0x$CID) + RNC=${CIDL:1:5} + RNC=$RNC" ($(printf "%d" 0x$RNC))" + CID=${CIDL:6:2} + CID="Short $(printf "%X" 0x$CID) ($(printf "%d" 0x$CID)), Long $(printf "%X" 0x$CIDL) ($(printf "%d" 0x$CIDL))" + +else + REGV=$(echo "$OX" | grep -o "+CREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{2,8\}") + if [ -n "$REGV" ]; then + LAC=$(echo "$REGV" | cut -d, -f3) + CID=$(echo "$REGV" | cut -d, -f4) + if [ ${#CID} -gt 4 ]; then + LAC=$(printf "%04X" 0x$LAC)" ($(printf "%d" 0x$LAC))" + CIDL=$(printf "%08X" 0x$CID) + RNC=${CIDL:1:3} + CID=${CIDL:4:4} + CID="Short $(printf "%X" 0x$CID) ($(printf "%d" 0x$CID)), Long $(printf "%X" 0x$CIDL) ($(printf "%d" 0x$CIDL))" + else + LAC="" + fi + else + LAC="" + fi +fi +REGSTAT=$(echo "$REGV" | cut -d, -f2) +if [ "$REGSTAT" == "5" -a "$COPS" != "-" ]; then + COPS_MNC=$COPS_MNC" (Roaming)" +fi +if [ -n "$CID" -a -n "$CID5" ] && [ "$RAT" == "13" -o "$RAT" == "10" ]; then + LAC="4G $LAC, 5G $LAC5" + CID="4G $CID
                                                                        5G $CID5" + RNC="4G $RNC, 5G $RNC5" +elif [ -n "$CID5" ]; then + LAC=$LAC5 + CID=$CID5 + RNC=$RNC5 +fi +if [ -z "$LAC" ]; then + LAC="-" + CID="-" + RNC="-" +fi + +{ + echo 'COPS="'"$COPS"'"' + echo 'COPS_MCC="'"$COPS_MCC"'"' + echo 'COPS_MNC="'"$COPS_MNC"'"' + echo 'LAC="'"$LAC"'"' + echo 'LAC_NUM="'""'"' + echo 'CID="'"$CID"'"' + echo 'CID_NUM="'""'"' + echo 'RNC="'"$RNC"'"' + echo 'RNC_NUM="'""'"' +} > /tmp/cell$CURRMODEM.file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/celltype.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/celltype.lua new file mode 100644 index 0000000..62b8ab5 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/celltype.lua @@ -0,0 +1,142 @@ +#!/usr/bin/lua + +modem = arg[1] +numb = arg[2] +echo = 0 + +datalist = {} +celllist = {} + +datalist[1] = "320u" +celllist[1] = 2 +datalist[2] = "330u" +celllist[2] = 2 +datalist[3] = "e3276" +celllist[3] = 3 +datalist[4] = "e398" +celllist[4] = 3 +datalist[5] = "e389" +celllist[5] = 3 +datalist[6] = "e392" +celllist[6] = 3 +datalist[7] = "e397" +celllist[7] = 3 +datalist[8] = "e8278" +celllist[8] = 3 +datalist[9] = "mf820" +celllist[9] = 3 +datalist[10] = "mf821" +celllist[10] = 3 +datalist[11] = "k5005" +celllist[11] = 3 +datalist[12] = "k5007" +celllist[12] = 3 +datalist[13] = "l800" +celllist[13] = 3 +datalist[14] = "e398" +celllist[14] = 3 +datalist[15] = "mf880" +celllist[15] = 3 +datalist[16] = "e3272" +celllist[16] = 3 +datalist[17] = "e3372" +celllist[17] = 3 +datalist[18] = "lte" +celllist[18] = 3 +datalist[19] = "340u" +celllist[19] = 2 +datalist[20] = "mf91d" +celllist[20] = 3 +datalist[21] = "mf825a" +celllist[21] = 3 +datalist[22] = "mf826" +celllist[22] = 3 +datalist[23] = "313u" +celllist[23] = 2 +datalist[24] = "341u" +celllist[24] = 2 +datalist[25] = "em74" +celllist[25] = 2 +datalist[26] = "mc74" +celllist[26] = 2 +datalist[27] = "em75" +celllist[27] = 2 +datalist[28] = "ec2" +celllist[28] = 3 +datalist[29] = "em06" +celllist[29] = 2 +datalist[30] = "ep06" +celllist[30] = 2 +datalist[31] = "slm750" +celllist[31] = 3 +datalist[32] = "bg96" +celllist[32] = 3 +datalist[33] = "em12" +celllist[33] = 2 +datalist[34] = "em20" +celllist[34] = 2 +datalist[35] = "rm5" +celllist[35] = 4 +datalist[36] = "l850" +celllist[36] = 2 +datalist[37] = "l860" +celllist[37] = 2 +datalist[38] = "fm15" +celllist[38] = 4 +datalist[39] = "em18" +celllist[39] = 2 +datalist[40] = "4105" +celllist[40] = 2 +datalist[41] = "em919" +celllist[41] = 4 +datalist[42] = "em16" +celllist[42] = 2 +datalist[43] = "sim820" +celllist[43] = 4 +datalist[44] = "mc73" +celllist[44] = 2 +datalist[45] = "eg25" +celllist[45] = 2 +datalist[46] = "srm8" +celllist[46] = 4 +datalist[47] = "4087" +celllist[47] = 3 +datalist[48] = "rg5" +celllist[48] = 4 +datalist[49] = "eg12" +celllist[49] = 2 +datalist[50] = "eg18" +celllist[50] = 2 +datalist[51] = "megafon" +celllist[51] = 2 +datalist[52] = "ln9" +celllist[52] = 2 + +printf = function(s,...) + if echo == 0 then + io.write(s:format(...)) + else + ss = s:format(...) + os.execute("/usr/lib/rooter/logprint.sh " .. ss) + end +end + +found = 3 +index = 1 +line = datalist[index] +data = string.lower(modem) + +while line ~= nil do + s, e = string.find(data, line) + if s ~= nil then + found = celllist[index] + break + end + index = index + 1 + line = datalist[index] +end + +file = io.open("/tmp/celltype" .. numb, "w") +cell = string.format("%s%s%s%s", "CELL", "=\"", found, "\"") +file:write(cell.. "\n") +file:close() diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/huaweihostless.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/huaweihostless.sh new file mode 100644 index 0000000..aa3fd3f --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/huaweihostless.sh @@ -0,0 +1,205 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "hostless " "$@" +} + +TMPFILE="/tmp/XXXXXX" + +handle_timeout(){ + local wget_pid="$1" + local count=0 + ps | grep -v grep | grep $wget_pid + res="$?" + while [ "$res" = 0 -a $count -lt "$((TIMEOUT))" ]; do + sleep 1 + count=$((count+1)) + ps | grep -v grep | grep $wget_pid + res="$?" + done + + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill "$wget_pid" 2> /dev/null + ps | grep -v grep | grep $wget_pid + res="$?" + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill -9 $wget_pid 2> /dev/null + fi + fi +} + +make_status() { + echo "$IP" > /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$CSQ" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$MODEM" >> /tmp/status$CURRMODEM.file + echo "$COPS" >> /tmp/status$CURRMODEM.file + echo "$NETWORK" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$COPS_MCC" >> /tmp/status$CURRMODEM.file + echo "$COPS_MNC" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo " " >> /tmp/status$CURRMODEM.file + echo " " >> /tmp/status$CURRMODEM.file + echo "$MONSTAT" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$CONN" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "Hostless/Phone" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file +} + +get_signal() { + TIMEOUT=3 + wget http://$IP/api/monitoring/status --load-cookies cookie -O $TMPFILE > /dev/null 2>&1 & + handle_timeout "$!" + local in_CurrentNetworkType="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" + if [ -z $in_CurrentNetworkType ]; then + NETWORK="-" + else + [ "$in_CurrentNetworkType" = "19" ] && NETWORK="LTE" # LTE + [ "$in_CurrentNetworkType" = "9" ] && NETWORK="HSPA+" # HSPA+ + [ "$in_CurrentNetworkType" = "7" ] && NETWORK="HSPA" # HSPA + [ "$in_CurrentNetworkType" = "6" ] && NETWORK="HSUPA" # HSUPA + [ "$in_CurrentNetworkType" = "5" ] && NETWORK="HSDPA" # HSDPA + [ "$in_CurrentNetworkType" = "4" ] && NETWORK="WCDMA" # WCDMA + [ "$in_CurrentNetworkType" = "3" ] && NETWORK="EDGE" # EDGE + [ "$in_CurrentNetworkType" = "2" ] && NETWORK="GPRS" # GPRS + [ "$in_CurrentNetworkType" = "1" ] && NETWORK="GSM" # GSM + fi + SIGNAL="" + local in_SignalStrength="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" + [ "$in_SignalStrength" != "" ] && SIGNAL="$in_SignalStrength" + + if [ "$SIGNAL" = "" ]; then + in_SignalStrength="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" + [ "$in_SignalStrength" != "" ] && SIGNAL="$((in_SignalStrength*20))" + fi + [ -z $SIGNAL ] && SIGNAL=0 + rm -f $TMPFILE +} + +CURRMODEM=$1 +PROTO=$2 +CONN="Modem #"$CURRMODEM + +MANUF=$(uci get modem.modem$CURRMODEM.manuf) +MODEL=$(uci get modem.modem$CURRMODEM.model) +MODEM=$MANUF" "$MODEL +IP=$(uci get modem.modem$CURRMODEM.ip) + +STARTIMEX=$(date +%s) +MONSTAT="Unknown" +rm -f /tmp/monstat$CURRMODEM + +sleep 5 +TIMEOUT=5 +wget -q http://$IP/html/home.html -O nul --save-cookies cookie --keep-session-cookies +sleep 5 +wget http://$IP/api/net/current-plmn -O $TMPFILE --load-cookies cookie > /dev/null 2>&1 & +handle_timeout "$!" + +wget http://$IP/api/device/information -O $TMPFILE --load-cookies cookie > /dev/null 2>&1 & +handle_timeout "$!" +in_mod="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" +if [ "$in_mod" != "" ]; then + MODEM=$MANUF" "$in_mod +fi +IMEI="Unknown" +IMSI="Unknown" +ICCID="Unknown" +CNUM="*" +CNUMx="*" +in_im="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" +if [ "$in_im" != "" ]; then + IMEI=$in_im +fi +in_im="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" +if [ "$in_im" != "" ]; then + IMSI=$in_im +fi +in_im="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" +if [ "$in_im" != "" ]; then + ICCID=$in_im +fi +in_im="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" +if [ "$in_im" != "" ]; then + CNUM=$in_im +fi + + +IDP=$(uci get modem.modem$CURRMODEM.idP) +IDV=$(uci get modem.modem$CURRMODEM.idV) + +echo $IDV" : "$IDP > /tmp/msimdatax$CURRMODEM +echo "$IMEI" >> /tmp/msimdatax$CURRMODEM +echo "$IMSI" >> /tmp/msimdatax$CURRMODEM +echo "$ICCID" >> /tmp/msimdatax$CURRMODEM +echo "1" >> /tmp/msimdatax$CURRMODEM +mv -f /tmp/msimdatax$CURRMODEM /tmp/msimdata$CURRMODEM +echo "$CNUM" > /tmp/msimnumx$CURRMODEM +echo "$CNUMx" >> /tmp/msimnumx$CURRMODEM +mv -f /tmp/msimnumx$CURRMODEM /tmp/msimnum$CURRMODEM + +sleep 20 +TIMEOUT=20 +wget http://$IP/api/net/current-plmn -O $TMPFILE --load-cookies cookie > /dev/null 2>&1 & +handle_timeout "$!" +COPS="" +in_provider="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" +[ "$in_provider" != "" ] && COPS="$in_provider" + +if [ "$COPS" = "" ]; then + COPS="-" + in_provider="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" + [ "$in_provider" != "" ] && COPS="$in_provider)" +fi +COPS_MCC="-" +COPS_MNC="-" +in_mcc="`cat $TMPFILE | grep \"\" | cut -d \">\" -f 2 | cut -d \"<\" -f 1`" +if [ "$in_mcc" != "" ]; then + COPS_MCC=${in_mcc:0:3} + COPS_MNC=${in_mcc:3:3} +fi +COPS_MNC=" "$COPS_MNC +TIMEOUT=5 + +while [ 1 = 1 ]; do + get_signal + CSQ="$SIGNAL" + if [ -e /tmp/monstat$CURRMODEM ]; then + source /tmp/monstat$CURRMODEM + fi + if [ -z $MONSTAT ]; then + MONSTAT="Unknown" + fi + make_status + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEX + while [ $ELAPSE -lt 10 ]; do + sleep 2 + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEX + done + STARTIMEX=$CURRTIME +done diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/mccmnc.data b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/mccmnc.data new file mode 100644 index 0000000..b4cdb19 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/mccmnc.data @@ -0,0 +1,11 @@ +50501;Telstra +50502;Optus +50503;Vodafone +50506;3 +302220;Telus +302610;Bell +302720;Rogers Communication +24004;SWEDEN +24005;Sweden 3G +24008;Telenor SE +51503;Smart \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/modemsignal.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/modemsignal.sh new file mode 100644 index 0000000..bf643ab --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/modemsignal.sh @@ -0,0 +1,287 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "modem signal" "$@" +} + +CURRMODEM=$1 +PROTO=$2 +CONN="Modem #"$CURRMODEM +STARTIME=$(date +%s) +STARTIMEX=$(date +%s) +SMSTIME=0 +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) +NUMB=0 +MONSTAT="Unknown" +rm -f /tmp/monstat$CURRMODEM + +make_connect() { + { + echo "Changing Port" + echo "-" + echo "-" + echo "-" + echo "$MODEM" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo " " + echo " " + echo "-" + echo "-" + echo "-" + echo "$CONN" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + echo "-" + } > /tmp/statusx$CURRMODEM.file + mv -f /tmp/statusx$CURRMODEM.file /tmp/status$CURRMODEM.file +} + +make_signal() { + { + if [ -e $ROOTER/provchk.sh ]; then + $ROOTER/provchk.sh $COPS $CURRMODEM + source /tmp/cops$CURRMODEM.file + rm -f /tmp/cops$CURRMODEM.file + fi + echo "$COMMPORT" + echo "$CSQ" + echo "$CSQ_PER" + echo "$CSQ_RSSI" + echo "$MODEM" + echo "$COPS" + echo "$MODE" + echo "$LAC" + echo "$LAC_NUM" + echo "$CID" + echo "$CID_NUM" + echo "$COPS_MCC" + echo "$COPS_MNC" + echo "$RNC" + echo "$RNC_NUM" + echo "$DOWN" + echo "$UP" + echo "$ECIO" + echo "$RSCP" + echo "$ECIO1" + echo "$RSCP1" + echo "$MONSTAT" + echo "$CELL" + echo "$MODTYPE" + echo "$CONN" + echo "$CHANNEL" + echo "$CNUM" + echo "$CNAM" + echo "$LBAND" + echo "$TEMP" + echo "$PROTO" + echo "$PCI" + echo "$SINR" + echo "$LATITUDE" + echo "$LONGITUDE" + } > /tmp/statusx$CURRMODEM.file + mv -f /tmp/statusx$CURRMODEM.file /tmp/status$CURRMODEM.file + if [ -e $ROOTER/modem-led.sh ]; then + $ROOTER/modem-led.sh $CURRMODEM 4 $CSQ + fi +} + +get_basic() { + $ROOTER/signal/basedata.sh $CURRMODEM $COMMPORT + if [ -e /tmp/base$CURRMODEM.file ]; then + source /tmp/base$CURRMODEM.file + rm -f /tmp/base$CURRMODEM.file + fi + $ROOTER/signal/celldata.sh $CURRMODEM $COMMPORT + if [ -e /tmp/cell$CURRMODEM.file ]; then + source /tmp/cell$CURRMODEM.file + rm -f /tmp/cell$CURRMODEM.file + fi + lua $ROOTER/signal/celltype.lua "$MODEM" $CURRMODEM + if [ -e /tmp/celltype$CURRMODEM ]; then + source /tmp/celltype$CURRMODEM + rm -f /tmp/celltype$CURRMODEM + fi +} + +get_basic +while [ 1 = 1 ]; do + get_basic + if [ -e /tmp/port$CURRMODEM.file ]; then + source /tmp/port$CURRMODEM.file + rm -f /tmp/port$CURRMODEM.file + COMMPORT="/dev/ttyUSB"$PORT + uci set modem.modem$CURRMODEM.commport=$PORT + make_connect + get_basic + STARTIME=$(date +%s) + else + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIME + if [ $ELAPSE -ge 60 ]; then + STARTIME=$CURRTIME + $ROOTER/signal/celldata.sh $CURRMODEM $COMMPORT + if [ -e /tmp/cell$CURRMODEM.file ]; then + source /tmp/cell$CURRMODEM.file + rm -f /tmp/cell$CURRMODEM.file + fi + fi + if [ -e /tmp/port$CURRMODEM.file ]; then + source /tmp/port$CURRMODEM.file + rm -f /tmp/port$CURRMODEM.file + COMMPORT="/dev/ttyUSB"$PORT + uci set modem.modem$CURRMODEM.commport=$PORT + make_connect + get_basic + STARTIME=$(date +%s) + else + VENDOR=$(uci get modem.modem$CURRMODEM.idV) + PROD=$(uci get modem.modem$CURRMODEM.idP) +# This case statement should be kept in sync with: $ROOTER/luci/celltype.sh + case $VENDOR in + "1199"|"0f3d" ) + $ROOTER/common/sierradata.sh $CURRMODEM $COMMPORT + ;; + "19d2" ) + if [ $PROD = 1432 ]; then + $ROOTER/common/mdm9215data.sh $CURRMODEM $COMMPORT + else + $ROOTER/common/ztedata.sh $CURRMODEM $COMMPORT + fi + ;; + "12d1" ) + $ROOTER/common/huaweidata.sh $CURRMODEM $COMMPORT + ;; + "2c7c" ) + $ROOTER/common/quecteldata.sh $CURRMODEM $COMMPORT + ;; + "2cb7"|"1508" ) + $ROOTER/common/fibocomdata.sh $CURRMODEM $COMMPORT + ;; + "2dee" ) + $ROOTER/common/meigdata.sh $CURRMODEM $COMMPORT + ;; + "05c6" ) + case $PROD in + "f601" ) + $ROOTER/common/meigdata.sh $CURRMODEM $COMMPORT + ;; + "5042" ) + $ROOTER/common/mdm9215data.sh $CURRMODEM $COMMPORT + ;; + "9090"|"9003"|"9215" ) + $ROOTER/common/quecteldata.sh $CURRMODEM $COMMPORT + ;; + "90db" ) + $ROOTER/common/simcomdata.sh $CURRMODEM $COMMPORT + ;; + * ) + $ROOTER/common/otherdata.sh $CURRMODEM $COMMPORT + ;; + esac + ;; + "1bc7" ) + case $PROD in + "1900"|"1901"|"1910"|"1911" ) + $ROOTER/common/t77data.sh $CURRMODEM $COMMPORT + ;; + * ) + $ROOTER/common/telitdata.sh $CURRMODEM $COMMPORT + ;; + esac + ;; + "1410" ) + $ROOTER/common/novateldata.sh $CURRMODEM $COMMPORT + ;; + "413c" ) + case $PROD in + "81d7"|"81d8" ) + $ROOTER/common/t77data.sh $CURRMODEM $COMMPORT + ;; + * ) + $ROOTER/common/sierradata.sh $CURRMODEM $COMMPORT + ;; + esac + ;; + "0489" |"03f0" ) + $ROOTER/common/t77data.sh $CURRMODEM $COMMPORT + ;; + "1e0e" ) + $ROOTER/common/simcomdata.sh $CURRMODEM $COMMPORT + ;; + "8087" ) + if [ $PROD = "095a" ]; then + $ROOTER/common/fibocomdata.sh $CURRMODEM $COMMPORT + fi + ;; + "0408" ) + $ROOTER/common/quantadata.sh $CURRMODEM $COMMPORT + ;; + * ) + $ROOTER/common/otherdata.sh $CURRMODEM $COMMPORT + ;; + esac + CHANNEL="-" + PCI="-" + LBAND="-" + TEMP="-" + SINR="-" + LATITUDE="-" + LONGITUDE="-" + if [ -e /tmp/signal$CURRMODEM.file ]; then + source /tmp/signal$CURRMODEM.file + rm -f /tmp/signal$CURRMODEM.file + fi + if [ -e /tmp/phonenumber$CURRMODEM ]; then + source /tmp/phonenumber$CURRMODEM + rm -f /tmp/phonenumber$CURRMODEM + fi + if [ -e /tmp/gpsdata ]; then + source /tmp/gpsdata + fi + make_signal + uci set modem.modem$CURRMODEM.cmode="1" + uci commit modem + if [ -e /tmp/monstat$CURRMODEM ]; then + source /tmp/monstat$CURRMODEM + fi + if [ -z "$MONSTAT" ]; then + MONSTAT="Unknown" + fi + fi + fi + if [ -e /etc/netspeed ]; then + NETSPEED=60 + else + NETSPEED=10 + fi + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEX + while [ $ELAPSE -lt $NETSPEED ]; do + sleep 2 + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEX + done + STARTIMEX=$CURRTIME +done diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/otherhostless.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/otherhostless.sh new file mode 100644 index 0000000..621d626 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/otherhostless.sh @@ -0,0 +1,160 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "hostless " "$@" +} + +get_basic() { + # get basic data here + # + # how it is done with other modems + # + COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) + $ROOTER/signal/basedata.sh $CURRMODEM $COMMPORT + source /tmp/base$CURRMODEM.file + rm -f /tmp/base$CURRMODEM.file + $ROOTER/signal/celldata.sh $CURRMODEM $COMMPORT + source /tmp/cell$CURRMODEM.file + rm -f /tmp/cell$CURRMODEM.file + lua $ROOTER/signal/celltype.lua "$MODEM" $CURRMODEM + source /tmp/celltype$CURRMODEM + rm -f /tmp/celltype$CURRMODEM +} + +make_signal() { + # get signal data here + # + # how it is done with other modems (Sierra) + # + COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) + MANUF=$(uci get modem.modem$CURRMODEM.manuf) + MODEL=$(uci get modem.modem$CURRMODEM.model) + MODEM=$MANUF" "$MODEL + $ROOTER/common/ubloxdata.sh $CURRMODEM $COMMPORT + source /tmp/signal$CURRMODEM.file + rm -f /tmp/signal$CURRMODEM.file + echo "$COMMPORT" > /tmp/statusx$CURRMODEM.file + echo "$CSQ" >> /tmp/statusx$CURRMODEM.file + echo "$CSQ_PER" >> /tmp/statusx$CURRMODEM.file + echo "$CSQ_RSSI" >> /tmp/statusx$CURRMODEM.file + echo "$MODEM" >> /tmp/statusx$CURRMODEM.file + echo "$COPS" >> /tmp/statusx$CURRMODEM.file + echo "$MODE" >> /tmp/statusx$CURRMODEM.file + echo "$LAC" >> /tmp/statusx$CURRMODEM.file + echo "$LAC_NUM" >> /tmp/statusx$CURRMODEM.file + echo "$CID" >> /tmp/statusx$CURRMODEM.file + echo "$CID_NUM" >> /tmp/statusx$CURRMODEM.file + echo "$COPS_MCC" >> /tmp/statusx$CURRMODEM.file + echo "$COPS_MNC" >> /tmp/statusx$CURRMODEM.file + echo "$RNC" >> /tmp/statusx$CURRMODEM.file + echo "$RNC_NUM" >> /tmp/statusx$CURRMODEM.file + echo "$DOWN" >> /tmp/statusx$CURRMODEM.file + echo "$UP" >> /tmp/statusx$CURRMODEM.file + echo "$ECIO" >> /tmp/statusx$CURRMODEM.file + echo "$RSCP" >> /tmp/statusx$CURRMODEM.file + echo "$ECIO1" >> /tmp/statusx$CURRMODEM.file + echo "$RSCP1" >> /tmp/statusx$CURRMODEM.file + echo "$MONSTAT" >> /tmp/statusx$CURRMODEM.file + echo "$CELL" >> /tmp/statusx$CURRMODEM.file + echo "$MODTYPE" >> /tmp/statusx$CURRMODEM.file + echo "$CONN" >> /tmp/statusx$CURRMODEM.file + echo "$CHANNEL" >> /tmp/statusx$CURRMODEM.file + echo "$CNUM" >> /tmp/statusx$CURRMODEM.file + echo "$CNAM" >> /tmp/statusx$CURRMODEM.file + echo "$LBAND" >> /tmp/statusx$CURRMODEM.file + echo "$TEMP" >> /tmp/statusx$CURRMODEM.file + echo "$PROTO" >> /tmp/statusx$CURRMODEM.file + echo "$PCI" >> /tmp/statusx$CURRMODEM.file + echo "-" >> /tmp/statusx$CURRMODEM.file + echo "-" >> /tmp/statusx$CURRMODEM.file + mv -f /tmp/statusx$CURRMODEM.file /tmp/status$CURRMODEM.file +} + +CURRMODEM=$1 +PROTO=$2 +CONN="Modem #"$CURRMODEM + +MANUF=$(uci get modem.modem$CURRMODEM.manuf) +MODEL=$(uci get modem.modem$CURRMODEM.model) +MODEM=$MANUF" "$MODEL +IP=$(uci get modem.modem$CURRMODEM.ip) +MONSTAT="Unknown" +rm -f /tmp/monstat$CURRMODEM + +idV=$(uci get modem.modem$CURRMODEM.idV) +idP=$(uci get modem.modem$CURRMODEM.idP) +if [ $idV = 1546 -a $idP = 1146 ]; then + get_basic +fi + + +STARTIMEX=$(date +%s) +MONSTAT="Unknown" +rm -f /tmp/monstat$CURRMODEM + +while [ 1 = 1 ]; do + if [ $idV = 1546 -a $idP = 1146 ]; then +# ublox + make_signal + else + echo "$IP" > /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$MODEM" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo " " >> /tmp/status$CURRMODEM.file + echo " " >> /tmp/status$CURRMODEM.file + echo "$MONSTAT" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$CONN" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "Hostless/Phone" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + fi + if [ -e /tmp/monstat$CURRMODEM ]; then + source /tmp/monstat$CURRMODEM + fi + if [ -z $MONSTAT ]; then + MONSTAT="Unknown" + fi + CURRTIME=$(date +%s) + + if [ -e /etc/netspeed ]; then + NETSPEED=60 + else + NETSPEED=10 + fi + + + + let ELAPSE=CURRTIME-STARTIMEX + while [ $ELAPSE -lt $NETSPEED ]; do + sleep 2 + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEX + done + STARTIMEX=$CURRTIME +done diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/status.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/status.sh new file mode 100644 index 0000000..2b61da8 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/status.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +CURRMODEM=$1 +MSG=$2 +MSG1=$3 +COMMPORT="/dev/ttyUSB"$(uci -q get modem.modem$CURRMODEM.commport) +if [ -z $MSG1 ]; then + MSG1="-" + COMMPORT="-" +fi + +echo "$COMMPORT" > /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "$MSG" >> /tmp/status$CURRMODEM.file +echo "$MSG1" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo " " >> /tmp/status$CURRMODEM.file +echo " " >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "Modem $CURRMODEM" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file +echo "-" >> /tmp/status$CURRMODEM.file diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/ztehostless.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/ztehostless.sh new file mode 100644 index 0000000..cedd8e9 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/signal/ztehostless.sh @@ -0,0 +1,215 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + logger -t "hostless " "$@" +} + +TMPFILE="/tmp/XXXXXX" +TMPFILE1="/tmp/XXXXXX1" + +make_status() { + echo "$IP" > /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$CSQ" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$MODEM" >> /tmp/status$CURRMODEM.file + echo "$PROV" >> /tmp/status$CURRMODEM.file + echo "$NETWORK" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo " " >> /tmp/status$CURRMODEM.file + echo " " >> /tmp/status$CURRMODEM.file + echo "$MONSTAT" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "$CONN" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "Hostless/Phone" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file + echo "-" >> /tmp/status$CURRMODEM.file +} + +handle_timeout(){ + local wget_pid="$1" + local count=0 + ps | grep -v grep | grep $wget_pid + res="$?" + while [ "$res" = 0 -a $count -lt "$((TIMEOUT))" ]; do + sleep 1 + count=$((count+1)) + ps | grep -v grep | grep $wget_pid + res="$?" + done + + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill "$wget_pid" 2> /dev/null + ps | grep -v grep | grep $wget_pid + res="$?" + if [ "$res" = 0 ]; then + log "Killing process on timeout" + kill -9 $wget_pid 2> /dev/null + fi + fi +} + +get_zte_model() { + uci set modem.modem$CURRMODEM.ztemodel=UNKNOWN + uci commit modem + SERIAL=$(uci get modem.modem$CURRMODEM.serial) + if [ $PROD = 1405 ]; then + if [ "`echo $SERIAL | grep P680A1ZTED`" != "" ]; then + uci set modem.modem$CURRMODEM.ztemodel=MF669 + uci set modem.modem$CURRMODEM.model=MF669/MF70 + uci commit modem + else + uci set modem.modem$CURRMODEM.ztemodel=V5 + uci set modem.modem$CURRMODEM.model=MF823/MF825/MF93D + uci commit modem + fi + fi + if [ $PROD = 0349 ]; then + uci set modem.modem$CURRMODEM.ztemodel=MF821D + uci set modem.modem$CURRMODEM.model=MF821D + uci commit modem + fi + if [ $PROD = 0166 ]; then + if [ "`echo $MODEL | grep MF91`" != "" ]; then + uci set modem.modem$CURRMODEM.ztemodel=MF91D + uci set modem.modem$CURRMODEM.model=MF91D + uci commit modem + else + if [ "`echo $MODEL | grep MF91`" != "" ]; then + uci set modem.modem$CURRMODEM.ztemodel=MF91 + uci set modem.modem$CURRMODEM.model=MF91 + uci commit modem + fi + fi + fi + if [ $PROD = 1408 ]; then + if [ "`echo $SERIAL | grep P680A1ZTED`" != "" ]; then + uci set modem.modem$CURRMODEM.ztemodel=V5 + uci set modem.modem$CURRMODEM.model=MF93D + uci commit modem + fi + fi +} + +get_basic(){ + ZTEMOD=$(uci get modem.modem$CURRMODEM.ztemodel) + TIMEOUT=3 + case $ZTEMOD in + "MF669" ) + wget http://$IP/logo_data.asp -O $TMPFILE > /dev/null 2>&1 & + handle_timeout "$!" + LUCKNUM="`cat $TMPFILE | grep lucknum | cut -d \' -f 2`" + ;; + "V5" ) + wget "http://$IP/goform/goform_get_cmd_process?isTest=false&cmd=network_type%2Cwan_ipaddr%2Cppp_status%2Cprefer_dns_auto%2Cstandby_dns_auto%2Csignalbar&multi_data=1&_=1376406501348" -O $TMPFILE > /dev/null 2>&1 & + handle_timeout "$!" + ;; + "MF821D"|"MF91D"|"MF91" ) + wget http://$IP/goform/status_update -O $TMPFILE > /dev/null 2>&1 & + handle_timeout "$!" + ;; + esac + PROV="`cat $TMPFILE | grep network_provider | cut -d \' -f 2`" + [ -z $PROV ] && PROV="-" + rm -f $TMPFILE +} + +get_signal(){ + TIMEOUT=3 + case $ZTEMOD in + "MF669" ) + wget http://$IP/logo_data.asp -O $TMPFILE > /dev/null 2>&1 & + handle_timeout "$!" + SIGNAL="`cat $TMPFILE | grep signalbar | cut -d \' -f 2`" + NETWORK="`cat $TMPFILE | grep network_type | cut -d \' -f 2`" + ;; + "V5" ) + wget "http://$IP/goform/goform_get_cmd_process?isTest=false&cmd=signalbar,wan_csq,network_type,network_provider,ppp_status,modem_main_state,rmcc,rmnc,,domain_stat,cell_id,rssi,rscp,lte_rssi,lte_rsrq,lte_rsrp,lte_snr,ecio,sms_received_flag,sts_received_flag,simcard_roam&multi_data=1&sms_received_flag_flag=0&sts_received_flag_flag=0" -O $TMPFILE > /dev/null 2>&1 & + handle_timeout "$!" + SIGNAL="`cat $TMPFILE | grep signalbar'\"\:\"[^\"]*' -o | cut -d'"' -f 3`" + NETWORK="`cat $TMPFILE | grep network_type'\"\:\"[^\"]*' -o | cut -d'"' -f 3`" + ;; + "MF821D"|"MF91D"|"MF91" ) + wget http://$IP/goform/status_update -O $TMPFILE > /dev/null 2>&1 & + handle_timeout "$!" + SIGNAL="`cat $TMPFILE | cut -d \; -f 1-1`" + net="`cat $TMPFILE | cut -d \; -f 4-4`" + if [ -z $net ]; then + NETWORK="-" + else + [ "$net" = "0" ] && NETWORK="No Service" + [ "$net" = "1" ] && NETWORK="LTE" + [ "$net" = "2" ] && NETWORK="EVDO" + [ "$net" = "3" ] && NETWORK="CDMA" + [ "$net" = "4" ] && NETWORK="WCDMA" + [ "$net" = "5" ] && NETWORK="GSM" + [ "$net" = "6" ] && NETWORK="HSDPA" + [ "$net" = "7" ] && NETWORK="HUSPA" + [ "$net" = "8" ] && NETWORK="HSPA+" + [ "$net" = "10" ] && NETWORK="EDGE" + [ "$net" = "11" ] && NETWORK="GPRS" + fi + ;; + esac + [ -z $SIGNAL ] && SIGNAL=0 + [ -z $NETWORK ] && NETWORK="-" + rm -f $TMPFILE +} + +CURRMODEM=$1 +PROTO=$2 +CONN="Modem #"$CURRMODEM + +PROD=$(uci get modem.modem$CURRMODEM.idP) +get_zte_model +MANUF=$(uci get modem.modem$CURRMODEM.manuf) +MODEL=$(uci get modem.modem$CURRMODEM.model) +MODEM=$MANUF" "$MODEL +IP=$(uci get modem.modem$CURRMODEM.ip) + +get_basic + +STARTIMEX=$(date +%s) +MONSTAT="Unknown" +rm -f /tmp/monstat$CURRMODEM + +while [ 1 = 1 ]; do + get_signal + CSQ="$SIGNAL Bars" + if [ -e /tmp/monstat$CURRMODEM ]; then + source /tmp/monstat$CURRMODEM + fi + if [ -z $MONSTAT ]; then + MONSTAT="Unknown" + fi + make_status + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEX + while [ $ELAPSE -lt 10 ]; do + sleep 2 + CURRTIME=$(date +%s) + let ELAPSE=CURRTIME-STARTIMEX + done + STARTIMEX=$CURRTIME +done diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/simlock.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/simlock.sh new file mode 100644 index 0000000..f79b761 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/simlock.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter + +log() { + modlog "SimLock $CURRMODEM" "$@" +} + +CURRMODEM=$1 +CPORT=$(uci get modem.modem$CURRMODEM.commport) + +ATCMDD="at+cpin?" +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +ERR=$(echo "$OX" | grep "ERROR") +if [ ! -z "$ERR" ]; then # No SIM + log "No SIM" + echo "2" > /tmp/simpin$CURRMODEM + exit 0 +fi +RDY=$(echo "$OX" | grep "READY") +if [ -z "$RDY" ]; then # SIM Locked + spin=$(uci -q get custom.simpin.pin) # SIM Pin + if [ -z "$spin" ]; then + spin=$(uci -q get modem.modeminfo$CURRMODEM.pincode) # Profile Pin + if [ -z "$spin" ]; then + spin=$(uci -q get profile.simpin.pin) # Default profile Pin + if [ -z "$spin" ]; then + echo "0" > /tmp/simpin$CURRMODEM # Locked/No Pin + log "Locked/No Pin" + exit 0 + fi + fi + fi + export PINCODE="$spin" # Use Pin to unlock + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "setpin.gcom" "$CURRMODEM") + sleep 5 + ATCMDD="at+cpin?" + OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") + RDY=$(echo "$OX" | grep "READY") + if [ -z "$RDY" ]; then # sim locked + echo "1" > /tmp/simpin$CURRMODEM # Incorrect Pin + log "Incorrect Pin" + exit 0 + fi + log "Correct Pin" +else + log "Not Locked" + sblk=$(uci -q get custom.simpin.block) + if [ "$sblk" = "1" ]; then + echo "4" > /tmp/simpin$CURRMODEM + log "Unlocked not allowed" + exit 0 + fi +fi +rm -f /tmp/simpin$CURRMODEM # not locked + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/simlockc.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/simlockc.sh new file mode 100644 index 0000000..af4651d --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/simlockc.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +log() { + logger -t "SIM Lock" "$@" +} diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/sms/check_sms.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/sms/check_sms.sh new file mode 100644 index 0000000..0475e85 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/sms/check_sms.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +ROOTER=/usr/lib/rooter +ROOTER_LINK="/tmp/links" + +CURRMODEM=$1 + +if [ -e /etc/nosms ]; then + uci set modem.modem$CURRMODEM.sms=0 + uci commit modem + exit 0 +fi + +CPORT=$(uci get modem.modem$CURRMODEM.commport) +sleep 10 +OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "smschk.gcom" "$CURRMODEM") + +ERROR="ERROR" +if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1` +then + uci set modem.modem$CURRMODEM.sms=0 + uci commit modem +else + uci set modem.modem$CURRMODEM.sms=1 + uci commit modem + if [ -e /usr/lib/sms/processsms ]; then + if [ ! -e $ROOTER_LINK/processsms$CURRMODEM ]; then + ln -s /usr/lib/sms/processsms $ROOTER_LINK/processsms$CURRMODEM + $ROOTER_LINK/processsms$CURRMODEM $CURRMODEM & + fi + fi +fi diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/timezone.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/timezone.sh new file mode 100644 index 0000000..a0f1800 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/timezone.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +sleep 10 +rm -f /tmp/timez +wget --no-check-certificate -O /tmp/timez http://ip-api.com/json > /dev/null 2>&1 +OX=$(cat /tmp/timez) + +TZ=$(echo $OX" " | tr -d '"' | grep -o 'timezone:[^;]*' | tr ":" ",") +ZONEN=$(echo "$TZ" | cut -d, -f2) + +/usr/lib/rooter/tzone.lua "$ZONEN" +source /tmp/tzone + +uci set system.@system[-1].timezone="$ZNAME" +uci set system.@system[-1].zonename="$ZONEN" +uci commit system +/etc/init.d/system restart + + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/tzone.lua b/rooter/ext-rooter-basic/files/usr/lib/rooter/tzone.lua new file mode 100644 index 0000000..279ad3c --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/tzone.lua @@ -0,0 +1,478 @@ +#!/usr/bin/lua + +TZ = { + { 'Africa/Abidjan', 'GMT0' }, + { 'Africa/Accra', 'GMT0' }, + { 'Africa/Addis Ababa', 'EAT-3' }, + { 'Africa/Algiers', 'CET-1' }, + { 'Africa/Asmara', 'EAT-3' }, + { 'Africa/Bamako', 'GMT0' }, + { 'Africa/Bangui', 'WAT-1' }, + { 'Africa/Banjul', 'GMT0' }, + { 'Africa/Bissau', 'GMT0' }, + { 'Africa/Blantyre', 'CAT-2' }, + { 'Africa/Brazzaville', 'WAT-1' }, + { 'Africa/Bujumbura', 'CAT-2' }, + { 'Africa/Cairo', 'EET-2' }, + { 'Africa/Casablanca', '<+01>-1' }, + { 'Africa/Ceuta', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Africa/Conakry', 'GMT0' }, + { 'Africa/Dakar', 'GMT0' }, + { 'Africa/Dar es Salaam', 'EAT-3' }, + { 'Africa/Djibouti', 'EAT-3' }, + { 'Africa/Douala', 'WAT-1' }, + { 'Africa/El Aaiun', '<+01>-1' }, + { 'Africa/Freetown', 'GMT0' }, + { 'Africa/Gaborone', 'CAT-2' }, + { 'Africa/Harare', 'CAT-2' }, + { 'Africa/Johannesburg', 'SAST-2' }, + { 'Africa/Juba', 'EAT-3' }, + { 'Africa/Kampala', 'EAT-3' }, + { 'Africa/Khartoum', 'CAT-2' }, + { 'Africa/Kigali', 'CAT-2' }, + { 'Africa/Kinshasa', 'WAT-1' }, + { 'Africa/Lagos', 'WAT-1' }, + { 'Africa/Libreville', 'WAT-1' }, + { 'Africa/Lome', 'GMT0' }, + { 'Africa/Luanda', 'WAT-1' }, + { 'Africa/Lubumbashi', 'CAT-2' }, + { 'Africa/Lusaka', 'CAT-2' }, + { 'Africa/Malabo', 'WAT-1' }, + { 'Africa/Maputo', 'CAT-2' }, + { 'Africa/Maseru', 'SAST-2' }, + { 'Africa/Mbabane', 'SAST-2' }, + { 'Africa/Mogadishu', 'EAT-3' }, + { 'Africa/Monrovia', 'GMT0' }, + { 'Africa/Nairobi', 'EAT-3' }, + { 'Africa/Ndjamena', 'WAT-1' }, + { 'Africa/Niamey', 'WAT-1' }, + { 'Africa/Nouakchott', 'GMT0' }, + { 'Africa/Ouagadougou', 'GMT0' }, + { 'Africa/Porto-Novo', 'WAT-1' }, + { 'Africa/Sao Tome', 'GMT0' }, + { 'Africa/Tripoli', 'EET-2' }, + { 'Africa/Tunis', 'CET-1' }, + { 'Africa/Windhoek', 'CAT-2' }, + { 'America/Adak', 'HST10HDT,M3.2.0,M11.1.0' }, + { 'America/Anchorage', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/Anguilla', 'AST4' }, + { 'America/Antigua', 'AST4' }, + { 'America/Araguaina', '<-03>3' }, + { 'America/Argentina/Buenos Aires', '<-03>3' }, + { 'America/Argentina/Catamarca', '<-03>3' }, + { 'America/Argentina/Cordoba', '<-03>3' }, + { 'America/Argentina/Jujuy', '<-03>3' }, + { 'America/Argentina/La Rioja', '<-03>3' }, + { 'America/Argentina/Mendoza', '<-03>3' }, + { 'America/Argentina/Rio Gallegos', '<-03>3' }, + { 'America/Argentina/Salta', '<-03>3' }, + { 'America/Argentina/San Juan', '<-03>3' }, + { 'America/Argentina/San Luis', '<-03>3' }, + { 'America/Argentina/Tucuman', '<-03>3' }, + { 'America/Argentina/Ushuaia', '<-03>3' }, + { 'America/Aruba', 'AST4' }, + { 'America/Asuncion', '<-04>4<-03>,M10.1.0/0,M3.4.0/0' }, + { 'America/Atikokan', 'EST5' }, + { 'America/Bahia', '<-03>3' }, + { 'America/Bahia Banderas', 'CST6CDT,M4.1.0,M10.5.0' }, + { 'America/Barbados', 'AST4' }, + { 'America/Belem', '<-03>3' }, + { 'America/Belize', 'CST6' }, + { 'America/Blanc-Sablon', 'AST4' }, + { 'America/Boa Vista', '<-04>4' }, + { 'America/Bogota', '<-05>5' }, + { 'America/Boise', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Cambridge Bay', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Campo Grande', '<-04>4' }, + { 'America/Cancun', 'EST5' }, + { 'America/Caracas', '<-04>4' }, + { 'America/Cayenne', '<-03>3' }, + { 'America/Cayman', 'EST5' }, + { 'America/Chicago', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Chihuahua', 'MST7MDT,M4.1.0,M10.5.0' }, + { 'America/Costa Rica', 'CST6' }, + { 'America/Creston', 'MST7' }, + { 'America/Cuiaba', '<-04>4' }, + { 'America/Curacao', 'AST4' }, + { 'America/Danmarkshavn', 'GMT0' }, + { 'America/Dawson', 'MST7' }, + { 'America/Dawson Creek', 'MST7' }, + { 'America/Denver', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Detroit', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Dominica', 'AST4' }, + { 'America/Edmonton', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Eirunepe', '<-05>5' }, + { 'America/El Salvador', 'CST6' }, + { 'America/Fort Nelson', 'MST7' }, + { 'America/Fortaleza', '<-03>3' }, + { 'America/Glace Bay', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'America/Goose Bay', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'America/Grand Turk', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Grenada', 'AST4' }, + { 'America/Guadeloupe', 'AST4' }, + { 'America/Guatemala', 'CST6' }, + { 'America/Guayaquil', '<-05>5' }, + { 'America/Guyana', '<-04>4' }, + { 'America/Halifax', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'America/Havana', 'CST5CDT,M3.2.0/0,M11.1.0/1' }, + { 'America/Hermosillo', 'MST7' }, + { 'America/Indiana/Indianapolis', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Knox', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Marengo', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Petersburg', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Tell City', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Vevay', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Vincennes', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Indiana/Winamac', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Inuvik', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Iqaluit', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Jamaica', 'EST5' }, + { 'America/Juneau', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/Kentucky/Louisville', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Kentucky/Monticello', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Kralendijk', 'AST4' }, + { 'America/La Paz', '<-04>4' }, + { 'America/Lima', '<-05>5' }, + { 'America/Los Angeles', 'PST8PDT,M3.2.0,M11.1.0' }, + { 'America/Lower Princes', 'AST4' }, + { 'America/Maceio', '<-03>3' }, + { 'America/Managua', 'CST6' }, + { 'America/Manaus', '<-04>4' }, + { 'America/Marigot', 'AST4' }, + { 'America/Martinique', 'AST4' }, + { 'America/Matamoros', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Mazatlan', 'MST7MDT,M4.1.0,M10.5.0' }, + { 'America/Menominee', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Merida', 'CST6CDT,M4.1.0,M10.5.0' }, + { 'America/Metlakatla', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/Mexico City', 'CST6CDT,M4.1.0,M10.5.0' }, + { 'America/Miquelon', '<-03>3<-02>,M3.2.0,M11.1.0' }, + { 'America/Moncton', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'America/Monterrey', 'CST6CDT,M4.1.0,M10.5.0' }, + { 'America/Montevideo', '<-03>3' }, + { 'America/Montserrat', 'AST4' }, + { 'America/Nassau', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/New York', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Nipigon', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Nome', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/Noronha', '<-02>2' }, + { 'America/North Dakota/Beulah', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/North Dakota/Center', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/North Dakota/New Salem', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Nuuk', '<-03>3<-02>,M3.5.0/-2,M10.5.0/-1' }, + { 'America/Ojinaga', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'America/Panama', 'EST5' }, + { 'America/Pangnirtung', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Paramaribo', '<-03>3' }, + { 'America/Phoenix', 'MST7' }, + { 'America/Port of Spain', 'AST4' }, + { 'America/Port-au-Prince', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Porto Velho', '<-04>4' }, + { 'America/Puerto Rico', 'AST4' }, + { 'America/Punta Arenas', '<-03>3' }, + { 'America/Rainy River', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Rankin Inlet', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Recife', '<-03>3' }, + { 'America/Regina', 'CST6' }, + { 'America/Resolute', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Rio Branco', '<-05>5' }, + { 'America/Santarem', '<-03>3' }, + { 'America/Santiago', '<-04>4<-03>,M9.1.6/24,M4.1.6/24' }, + { 'America/Santo Domingo', 'AST4' }, + { 'America/Sao Paulo', '<-03>3' }, + { 'America/Scoresbysund', '<-01>1<+00>,M3.5.0/0,M10.5.0/1' }, + { 'America/Sitka', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/St Barthelemy', 'AST4' }, + { 'America/St Johns', 'NST3:30NDT,M3.2.0,M11.1.0' }, + { 'America/St Kitts', 'AST4' }, + { 'America/St Lucia', 'AST4' }, + { 'America/St Thomas', 'AST4' }, + { 'America/St Vincent', 'AST4' }, + { 'America/Swift Current', 'CST6' }, + { 'America/Tegucigalpa', 'CST6' }, + { 'America/Thule', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'America/Thunder Bay', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Tijuana', 'PST8PDT,M3.2.0,M11.1.0' }, + { 'America/Toronto', 'EST5EDT,M3.2.0,M11.1.0' }, + { 'America/Tortola', 'AST4' }, + { 'America/Vancouver', 'PST8PDT,M3.2.0,M11.1.0' }, + { 'America/Whitehorse', 'MST7' }, + { 'America/Winnipeg', 'CST6CDT,M3.2.0,M11.1.0' }, + { 'America/Yakutat', 'AKST9AKDT,M3.2.0,M11.1.0' }, + { 'America/Yellowknife', 'MST7MDT,M3.2.0,M11.1.0' }, + { 'Antarctica/Casey', '<+08>-8' }, + { 'Antarctica/Davis', '<+07>-7' }, + { 'Antarctica/DumontDUrville', '<+10>-10' }, + { 'Antarctica/Macquarie', '<+11>-11' }, + { 'Antarctica/Mawson', '<+05>-5' }, + { 'Antarctica/McMurdo', 'NZST-12NZDT,M9.5.0,M4.1.0/3' }, + { 'Antarctica/Palmer', '<-03>3' }, + { 'Antarctica/Rothera', '<-03>3' }, + { 'Antarctica/Syowa', '<+03>-3' }, + { 'Antarctica/Troll', '<+00>0<+02>-2,M3.5.0/1,M10.5.0/3' }, + { 'Antarctica/Vostok', '<+06>-6' }, + { 'Arctic/Longyearbyen', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Asia/Aden', '<+03>-3' }, + { 'Asia/Almaty', '<+06>-6' }, + { 'Asia/Amman', 'EET-2EEST,M3.5.4/24,M10.5.5/1' }, + { 'Asia/Anadyr', '<+12>-12' }, + { 'Asia/Aqtau', '<+05>-5' }, + { 'Asia/Aqtobe', '<+05>-5' }, + { 'Asia/Ashgabat', '<+05>-5' }, + { 'Asia/Atyrau', '<+05>-5' }, + { 'Asia/Baghdad', '<+03>-3' }, + { 'Asia/Bahrain', '<+03>-3' }, + { 'Asia/Baku', '<+04>-4' }, + { 'Asia/Bangkok', '<+07>-7' }, + { 'Asia/Barnaul', '<+07>-7' }, + { 'Asia/Beirut', 'EET-2EEST,M3.5.0/0,M10.5.0/0' }, + { 'Asia/Bishkek', '<+06>-6' }, + { 'Asia/Brunei', '<+08>-8' }, + { 'Asia/Chita', '<+09>-9' }, + { 'Asia/Choibalsan', '<+08>-8' }, + { 'Asia/Colombo', '<+0530>-5:30' }, + { 'Asia/Damascus', 'EET-2EEST,M3.5.5/0,M10.5.5/0' }, + { 'Asia/Dhaka', '<+06>-6' }, + { 'Asia/Dili', '<+09>-9' }, + { 'Asia/Dubai', '<+04>-4' }, + { 'Asia/Dushanbe', '<+05>-5' }, + { 'Asia/Famagusta', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Asia/Gaza', 'EET-2EEST,M3.5.5/0,M10.5.6/1' }, + { 'Asia/Hebron', 'EET-2EEST,M3.5.5/0,M10.5.6/1' }, + { 'Asia/Ho Chi Minh', '<+07>-7' }, + { 'Asia/Hong Kong', 'HKT-8' }, + { 'Asia/Hovd', '<+07>-7' }, + { 'Asia/Irkutsk', '<+08>-8' }, + { 'Asia/Jakarta', 'WIB-7' }, + { 'Asia/Jayapura', 'WIT-9' }, + { 'Asia/Jerusalem', 'IST-2IDT,M3.4.4/26,M10.5.0' }, + { 'Asia/Kabul', '<+0430>-4:30' }, + { 'Asia/Kamchatka', '<+12>-12' }, + { 'Asia/Karachi', 'PKT-5' }, + { 'Asia/Kathmandu', '<+0545>-5:45' }, + { 'Asia/Khandyga', '<+09>-9' }, + { 'Asia/Kolkata', 'IST-5:30' }, + { 'Asia/Krasnoyarsk', '<+07>-7' }, + { 'Asia/Kuala Lumpur', '<+08>-8' }, + { 'Asia/Kuching', '<+08>-8' }, + { 'Asia/Kuwait', '<+03>-3' }, + { 'Asia/Macau', 'CST-8' }, + { 'Asia/Magadan', '<+11>-11' }, + { 'Asia/Makassar', 'WITA-8' }, + { 'Asia/Manila', 'PST-8' }, + { 'Asia/Muscat', '<+04>-4' }, + { 'Asia/Nicosia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Asia/Novokuznetsk', '<+07>-7' }, + { 'Asia/Novosibirsk', '<+07>-7' }, + { 'Asia/Omsk', '<+06>-6' }, + { 'Asia/Oral', '<+05>-5' }, + { 'Asia/Phnom Penh', '<+07>-7' }, + { 'Asia/Pontianak', 'WIB-7' }, + { 'Asia/Pyongyang', 'KST-9' }, + { 'Asia/Qatar', '<+03>-3' }, + { 'Asia/Qostanay', '<+06>-6' }, + { 'Asia/Qyzylorda', '<+05>-5' }, + { 'Asia/Riyadh', '<+03>-3' }, + { 'Asia/Sakhalin', '<+11>-11' }, + { 'Asia/Samarkand', '<+05>-5' }, + { 'Asia/Seoul', 'KST-9' }, + { 'Asia/Shanghai', 'CST-8' }, + { 'Asia/Singapore', '<+08>-8' }, + { 'Asia/Srednekolymsk', '<+11>-11' }, + { 'Asia/Taipei', 'CST-8' }, + { 'Asia/Tashkent', '<+05>-5' }, + { 'Asia/Tbilisi', '<+04>-4' }, + { 'Asia/Tehran', '<+0330>-3:30<+0430>,J79/24,J263/24' }, + { 'Asia/Thimphu', '<+06>-6' }, + { 'Asia/Tokyo', 'JST-9' }, + { 'Asia/Tomsk', '<+07>-7' }, + { 'Asia/Ulaanbaatar', '<+08>-8' }, + { 'Asia/Urumqi', '<+06>-6' }, + { 'Asia/Ust-Nera', '<+10>-10' }, + { 'Asia/Vientiane', '<+07>-7' }, + { 'Asia/Vladivostok', '<+10>-10' }, + { 'Asia/Yakutsk', '<+09>-9' }, + { 'Asia/Yangon', '<+0630>-6:30' }, + { 'Asia/Yekaterinburg', '<+05>-5' }, + { 'Asia/Yerevan', '<+04>-4' }, + { 'Atlantic/Azores', '<-01>1<+00>,M3.5.0/0,M10.5.0/1' }, + { 'Atlantic/Bermuda', 'AST4ADT,M3.2.0,M11.1.0' }, + { 'Atlantic/Canary', 'WET0WEST,M3.5.0/1,M10.5.0' }, + { 'Atlantic/Cape Verde', '<-01>1' }, + { 'Atlantic/Faroe', 'WET0WEST,M3.5.0/1,M10.5.0' }, + { 'Atlantic/Madeira', 'WET0WEST,M3.5.0/1,M10.5.0' }, + { 'Atlantic/Reykjavik', 'GMT0' }, + { 'Atlantic/South Georgia', '<-02>2' }, + { 'Atlantic/St Helena', 'GMT0' }, + { 'Atlantic/Stanley', '<-03>3' }, + { 'Australia/Adelaide', 'ACST-9:30ACDT,M10.1.0,M4.1.0/3' }, + { 'Australia/Brisbane', 'AEST-10' }, + { 'Australia/Broken Hill', 'ACST-9:30ACDT,M10.1.0,M4.1.0/3' }, + { 'Australia/Currie', 'AEST-10AEDT,M10.1.0,M4.1.0/3' }, + { 'Australia/Darwin', 'ACST-9:30' }, + { 'Australia/Eucla', '<+0845>-8:45' }, + { 'Australia/Hobart', 'AEST-10AEDT,M10.1.0,M4.1.0/3' }, + { 'Australia/Lindeman', 'AEST-10' }, + { 'Australia/Lord Howe', '<+1030>-10:30<+11>-11,M10.1.0,M4.1.0' }, + { 'Australia/Melbourne', 'AEST-10AEDT,M10.1.0,M4.1.0/3' }, + { 'Australia/Perth', 'AWST-8' }, + { 'Australia/Sydney', 'AEST-10AEDT,M10.1.0,M4.1.0/3' }, + { 'Etc/GMT', 'GMT0' }, + { 'Etc/GMT+1', '<-01>1' }, + { 'Etc/GMT+10', '<-10>10' }, + { 'Etc/GMT+11', '<-11>11' }, + { 'Etc/GMT+12', '<-12>12' }, + { 'Etc/GMT+2', '<-02>2' }, + { 'Etc/GMT+3', '<-03>3' }, + { 'Etc/GMT+4', '<-04>4' }, + { 'Etc/GMT+5', '<-05>5' }, + { 'Etc/GMT+6', '<-06>6' }, + { 'Etc/GMT+7', '<-07>7' }, + { 'Etc/GMT+8', '<-08>8' }, + { 'Etc/GMT+9', '<-09>9' }, + { 'Etc/GMT-1', '<+01>-1' }, + { 'Etc/GMT-10', '<+10>-10' }, + { 'Etc/GMT-11', '<+11>-11' }, + { 'Etc/GMT-12', '<+12>-12' }, + { 'Etc/GMT-13', '<+13>-13' }, + { 'Etc/GMT-14', '<+14>-14' }, + { 'Etc/GMT-2', '<+02>-2' }, + { 'Etc/GMT-3', '<+03>-3' }, + { 'Etc/GMT-4', '<+04>-4' }, + { 'Etc/GMT-5', '<+05>-5' }, + { 'Etc/GMT-6', '<+06>-6' }, + { 'Etc/GMT-7', '<+07>-7' }, + { 'Etc/GMT-8', '<+08>-8' }, + { 'Etc/GMT-9', '<+09>-9' }, + { 'Europe/Amsterdam', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Andorra', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Astrakhan', '<+04>-4' }, + { 'Europe/Athens', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Belgrade', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Berlin', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Bratislava', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Brussels', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Bucharest', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Budapest', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Busingen', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Chisinau', 'EET-2EEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Copenhagen', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Dublin', 'IST-1GMT0,M10.5.0,M3.5.0/1' }, + { 'Europe/Gibraltar', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Guernsey', 'GMT0BST,M3.5.0/1,M10.5.0' }, + { 'Europe/Helsinki', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Isle of Man', 'GMT0BST,M3.5.0/1,M10.5.0' }, + { 'Europe/Istanbul', '<+03>-3' }, + { 'Europe/Jersey', 'GMT0BST,M3.5.0/1,M10.5.0' }, + { 'Europe/Kaliningrad', 'EET-2' }, + { 'Europe/Kiev', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Kirov', '<+03>-3' }, + { 'Europe/Lisbon', 'WET0WEST,M3.5.0/1,M10.5.0' }, + { 'Europe/Ljubljana', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/London', 'GMT0BST,M3.5.0/1,M10.5.0' }, + { 'Europe/Luxembourg', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Madrid', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Malta', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Mariehamn', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Minsk', '<+03>-3' }, + { 'Europe/Monaco', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Moscow', 'MSK-3' }, + { 'Europe/Oslo', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Paris', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Podgorica', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Prague', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Riga', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Rome', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Samara', '<+04>-4' }, + { 'Europe/San Marino', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Sarajevo', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Saratov', '<+04>-4' }, + { 'Europe/Simferopol', 'MSK-3' }, + { 'Europe/Skopje', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Sofia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Stockholm', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Tallinn', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Tirane', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Ulyanovsk', '<+04>-4' }, + { 'Europe/Uzhgorod', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Vaduz', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Vatican', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Vienna', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Vilnius', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Volgograd', '<+04>-4' }, + { 'Europe/Warsaw', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Zagreb', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Europe/Zaporozhye', 'EET-2EEST,M3.5.0/3,M10.5.0/4' }, + { 'Europe/Zurich', 'CET-1CEST,M3.5.0,M10.5.0/3' }, + { 'Indian/Antananarivo', 'EAT-3' }, + { 'Indian/Chagos', '<+06>-6' }, + { 'Indian/Christmas', '<+07>-7' }, + { 'Indian/Cocos', '<+0630>-6:30' }, + { 'Indian/Comoro', 'EAT-3' }, + { 'Indian/Kerguelen', '<+05>-5' }, + { 'Indian/Mahe', '<+04>-4' }, + { 'Indian/Maldives', '<+05>-5' }, + { 'Indian/Mauritius', '<+04>-4' }, + { 'Indian/Mayotte', 'EAT-3' }, + { 'Indian/Reunion', '<+04>-4' }, + { 'Pacific/Apia', '<+13>-13<+14>,M9.5.0/3,M4.1.0/4' }, + { 'Pacific/Auckland', 'NZST-12NZDT,M9.5.0,M4.1.0/3' }, + { 'Pacific/Bougainville', '<+11>-11' }, + { 'Pacific/Chatham', '<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45' }, + { 'Pacific/Chuuk', '<+10>-10' }, + { 'Pacific/Easter', '<-06>6<-05>,M9.1.6/22,M4.1.6/22' }, + { 'Pacific/Efate', '<+11>-11' }, + { 'Pacific/Enderbury', '<+13>-13' }, + { 'Pacific/Fakaofo', '<+13>-13' }, + { 'Pacific/Fiji', '<+12>-12<+13>,M11.2.0,M1.2.3/99' }, + { 'Pacific/Funafuti', '<+12>-12' }, + { 'Pacific/Galapagos', '<-06>6' }, + { 'Pacific/Gambier', '<-09>9' }, + { 'Pacific/Guadalcanal', '<+11>-11' }, + { 'Pacific/Guam', 'ChST-10' }, + { 'Pacific/Honolulu', 'HST10' }, + { 'Pacific/Kiritimati', '<+14>-14' }, + { 'Pacific/Kosrae', '<+11>-11' }, + { 'Pacific/Kwajalein', '<+12>-12' }, + { 'Pacific/Majuro', '<+12>-12' }, + { 'Pacific/Marquesas', '<-0930>9:30' }, + { 'Pacific/Midway', 'SST11' }, + { 'Pacific/Nauru', '<+12>-12' }, + { 'Pacific/Niue', '<-11>11' }, + { 'Pacific/Norfolk', '<+11>-11<+12>,M10.1.0,M4.1.0/3' }, + { 'Pacific/Noumea', '<+11>-11' }, + { 'Pacific/Pago Pago', 'SST11' }, + { 'Pacific/Palau', '<+09>-9' }, + { 'Pacific/Pitcairn', '<-08>8' }, + { 'Pacific/Pohnpei', '<+11>-11' }, + { 'Pacific/Port Moresby', '<+10>-10' }, + { 'Pacific/Rarotonga', '<-10>10' }, + { 'Pacific/Saipan', 'ChST-10' }, + { 'Pacific/Tahiti', '<-10>10' }, + { 'Pacific/Tarawa', '<+12>-12' }, + { 'Pacific/Tongatapu', '<+13>-13' }, + { 'Pacific/Wake', '<+12>-12' }, + { 'Pacific/Wallis', '<+12>-12' }, +} + +name = arg[1] +TM = nil + +array = {} +i = 1 +repeat + array = TZ[i] + if array[1] == name then + TM = array[2] + break + end + i = i+1 +until(array == nil) + +local tfile = io.open("/tmp/tzone", "w") +if TM ~= nil then + tfile:write("ZNAME=\"", TM, "\"\n") + tfile:write("ZONEN=\"", name, "\"\n") +end +tfile:close() + diff --git a/rooter/ext-rooter-basic/files/usr/lib/rooter/ussd.sh b/rooter/ext-rooter-basic/files/usr/lib/rooter/ussd.sh new file mode 100644 index 0000000..fb685b0 --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/lib/rooter/ussd.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +CURRMODEM=$(uci get modem.general.modemnum) +COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport) +ROOTER=/usr/lib/rooter + +if [ -n "$1" ]; then + echo "$1" > /tmp/ussd_arg$CURRMODEM +fi + +while true; do + if [ -e /tmp/ussd_arg$CURRMODEM ]; then + read USSDSTR < /tmp/ussd_arg$CURRMODEM + rm /tmp/ussd_arg$CURRMODEM + fi + if [ -n "$USSDSTR" ]; then + ATCMDD="AT+CUSD=1,\"$USSDSTR\",15" + OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "ussd.gcom" "$CURRMODEM" "$ATCMDD" | tr "\n" "\v") + USSD=$(echo "$OX" | grep -o "+CUSD: .\+\",[0-9]\+" | tr "\v" "\n") + USSDL=${#USSD} + USSDLx=$((USSDL - 2)) + DCS=$(printf "${USSD:$USSDLx:2}") + if [ $USSDL -ge 14 ]; then + USSDL=$((USSDL - 14)) + USSD=$(printf "${USSD:10:$USSDL}") + if [ $DCS -eq "72" ]; then + USSDx="" + USSDL=${#USSD} + nV=0 + until [ $nV -ge $USSDL ]; do + UU=$(printf "%d" "0x"${USSD:$nV:4}) + if [[ $UU -lt 128 ]]; then + USSDx="$USSDx"$(printf "%b" "\\$(printf "0%o" "$UU")") + elif [[ $UU -lt 2048 ]]; then + UUU=$(((($UU & 1984) >> 6) | 192)) + USSDx="$USSDx"$(printf "%b" "\\$(printf "0%o" "$UUU")") + UUU=$((($UU & 63) | 128)) + USSDx="$USSDx"$(printf "%b" "\\$(printf "0%o" "$UUU")") + else + UUU=$(((($UU & 61440) >> 12) | 224)) + USSDx="$USSDx"$(printf "%b" "\\$(printf "0%o" "$UUU")") + UUU=$(((($UU & 4032) >> 6) | 128)) + USSDx="$USSDx"$(printf "%b" "\\$(printf "0%o" "$UUU")") + UUU=$((($UU & 63) | 128)) + USSDx="$USSDx"$(printf "%b" "\\$(printf "0%o" "$UUU")") + fi + nV=$(( $nV + 4 )) + done + USSD="$USSDx" + fi + else + USSD=$(echo "$OX" | tr "\v" "\n") + fi + echo + echo "-----------------------------------------------------------" + echo "$USSD" + echo "-----------------------------------------------------------" + echo + fi + printf "Enter blank to quit, or a USSD string to send: "; read USSDSTR + if [ -z "$USSDSTR" ]; then + break + fi +done +ATCMDD="AT+CUSD=2" +OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD") +exit 0 diff --git a/rooter/ext-rooter-basic/files/usr/sbin/modlog b/rooter/ext-rooter-basic/files/usr/sbin/modlog new file mode 100644 index 0000000..46a614f --- /dev/null +++ b/rooter/ext-rooter-basic/files/usr/sbin/modlog @@ -0,0 +1,7 @@ +#!/bin/sh + +name=$1 +text=$2 + +logger -t "$name" "$text" +/usr/lib/rooter/log/modlogger.sh "$name $text" \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/background/main_bg.jpg b/rooter/ext-rooter-basic/files/www/luci-static/background/main_bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..66222dcbef009ee206460169e829eeed027f2848 GIT binary patch literal 134812 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

                                                                        5p0_H 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 Oxtd{R3XbI-wg1_EhJN<| literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/css/cascade.css b/rooter/ext-rooter-basic/files/www/luci-static/css/cascade.css new file mode 100644 index 0000000..19b2b1e --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/css/cascade.css @@ -0,0 +1,3266 @@ +@import url(fonts.css?v=3); + +@import url(pure-min.css?v=1); + +:root { + --primary: #5e72e4; + --dark-primary: #483d8b; + --main-color: #09c; + --header-bg: #09c; + --header-color: #fff; + --bar-bg: #5e72e4; + --menu-bg-color: #fff; + --menu-color: #5f6368; + --menu-color-hover: #202124; + --main-menu-color: #202124; + --submenu-bg-hover: #d4d4d4; + --submenu-bg-hover-active: #09c; + --blue: #5e72e4; + --indigo: #5603ad; + --purple: #8965e0; + --pink: #f3a4b5; + --red: #f5365c; + --orange: #fb6340; + --yellow: #ffd600; + --green: #2dce89; + --teal: #11cdef; + --cyan: #2bffc6; + --gray: #8898aa; + --gray-dark: #32325d; + --lighter: #e9ecef; + --secondary: #f7fafc; + --success: #2dce89; + --info: #11cdef; + --warning: #fb6340; + --danger: #f5365c; + --light: #adb5bd; + --dark: #212529; + --default: #172b4d; + --white: #fff; + --neutral: #fff; + --darker: #000; + --background-color: #f4f5f7; + --login-form-bg-color: rgba(244,245,247,0.8); + --breakpoint-xs: 0; + --breakpoint-sm: 576px; + --breakpoint-md: 768px; + --breakpoint-lg: 992px; + --breakpoint-xl: 1200px; + --blur-radius: 10px; + --blur-opacity: .5; + --blur-radius-dark: 10px; + --blur-opacity-dark: .5; + --font-family-sans-serif: "Google Sans","Microsoft Yahei","WenQuanYi Micro Hei",sans-serif,"Helvetica Neue",Helvetica,"Hiragino Sans GB"; + --font-family-monospace: SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace; + --font-family-normal: Open Sans,PingFangSC-Regular,Microsoft Yahei,WenQuanYi Micro Hei,"Helvetica Neue",Helvetica,Hiragino Sans GB,sans-serif; +} + +html,body { + height: 100%; + font-size: 16px; + font-family: var(--font-family-sans-serif); + margin: 0px; + padding: 0px; +} + +html { + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +body { + font-size: .875rem; + background-color: var(--background-color); + color: var(--gray-dark); +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +::selection { + background-color: var(--primary); + color: var(--white); +} + +a:link,a:visited,a:active { + color: var(--primary); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +li { + list-style-type: none; +} + +.table { + position: relative; + display: table; +} + +.tr { + display: table-row; +} + +.thead { + display: table-header-group; +} + +.tbody { + display: table-row-group; +} + +.tfoot { + display: table-footer-group; +} + +.td,.th { + line-height: normal; + display: table-cell; + text-align: center; + vertical-align: middle; + padding: .5em; +} + +.th { + font-weight: 700; + white-space: nowrap; +} + +.tr.placeholder { + height: 4em; +} + +.tr.placeholder>.td { + line-height: 3; + position: absolute; + right: 0; + bottom: 0; + left: 0; + text-align: center!important; + background: inherit; + padding: .4rem 0!important; +} + +.td[width="33%"] { + padding: 1.1em 1.5rem; +} + +.table[width="33%"],.th[width="33%"],.td[width="33%"] { + width: 33%; +} + +.col-1 { + flex: 1 1 30px!important; +} + +.col-2 { + flex: 2 2 60px!important; +} + +.col-3 { + flex: 3 3 90px!important; +} + +.col-4 { + flex: 4 4 120px!important; +} + +.col-5 { + flex: 5 5 150px!important; +} + +.col-6 { + flex: 6 6 180px!important; +} + +.col-7 { + flex: 7 7 210px!important; +} + +.col-8 { + flex: 8 8 240px!important; +} + +.col-9 { + flex: 9 9 270px!important; +} + +.col-10 { + flex: 10 10 300px!important; +} + +.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6 { + font-family: inherit; + font-weight: 400; + line-height: 1.1!important; + color: inherit; +} + +select { + color: #555; + border: thin solid #ccc; + background-color: #fff; + background-image: none; + padding: .36rem .8rem; +} + +.btn,button,select,input,.cbi-dropdown { + line-height: 1.5rem; + color: #8898aa; + border: 1px solid #dee2e6; + border-radius: .25rem; + outline: 0; + background-image: none; + box-shadow: none; + transition: box-shadow .15s ease; + margin: .25rem .1rem; + padding: .5rem .75rem; +} + +select,.cbi-dropdown { + width: inherit; + cursor: default; +} + +select:not([multiple="multiple"]):focus,input:not(.cbi-button):focus,.cbi-dropdown:focus { + box-shadow: 0 3px 9px rgba(50,50,9,0),3px 4px 8px rgba(94,114,228,0.1); + border-color: var(--primary); +} + +pre { + overflow: auto; +} + +code { + font-size: 1rem; + font-size-adjust: .35; + color: #101010; + border-radius: 2px; + background: #ddd; + padding: 1px 3px; +} + +abbr { + cursor: help; + text-decoration: underline; + color: var(--primary); +} + +hr { + opacity: .1; + border-color: #eee; + margin: 1rem 0; +} + +.login-page { + height: 95vh; + width: 95vw; +} + +.login-page .video { + position: absolute; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background-color: var(--darker); + overflow: hidden; +} + +.login-page .video video { + width: 100%; + height: auto; +} + +.login-page .volume-control { + position: fixed; + right: 1rem; + top: 1rem; + width: 1.5rem; + height: 1.5rem; + z-index: 5000; + cursor: pointer; + background-size: contain; + background-image: url(../img/volume_high.svg); +} + +.login-page .volume-control.mute { + background-image: url(../img/volume_off.svg); +} + +.login-page .main-bg { + position: absolute; + width: 101vw; + height: 101vh; + left: 0; + top: 0; + background-image: url(../img/blank.png); + background-repeat: no-repeat; + background-position: center; + background-size: cover; + transition: all .5s; + background-color: rgba(255,255,255,1); +} + + +.login-page .status-container { + height: 100%; + position: absolute; + top: 0px; + + right: 0px; + display: flex; + flex-direction: column; + -webkit-box-pack: center; + justify-content: center; + align-items: flex-start; + min-height: 100%; + z-index: 2; + width: 800px; + box-shadow: rgba(0,0,0,0.75) 0 0 35px -5px; + margin-left: 5%; + background: transparent; +} + +.login-page .status-container .status-form { + display: flex; + flex-direction: column; + -webkit-box-align: center; + align-items: right; + position: absolute; + top: 0px; + width: 100%; + min-height: 100%; + max-width: 800px; + background-color: rgba(224,224,224,0); +} + +.login-page .login-container { + height: 100%; + position: absolute; + top: 0px; + display: flex; + flex-direction: column; + -webkit-box-pack: center; + justify-content: center; + align-items: flex-start; + min-height: 100%; + z-index: 2; + width: 20vw; + box-shadow: rgba(0,0,0,0.75) 0 0 35px -5px; + margin-left: 4%; + background: transparent; +} + +/* color of login panel */ +.login-page .login-container .login-form { + display: flex; + flex-direction: column; + -webkit-box-align: center; + align-items: center; + position: absolute; + top: 0px; + width: 100%; + min-height: 100%; + max-width: 100%; + background-color: rgba(224,224,224,0.7); +} + +/* change for login box */ +.login-page .login-container .login-form .brand { + display: flex; + -webkit-box-align: center; + align-items: center; + color: var(--default); + margin: 20px auto 5px 10px; +} + +.login-page .login-container .login-form .brandim { + display: flex; + -webkit-box-align: center; + align-items: center; + color: var(--default); + margin: 12vh 0px 30px 0px; +} + +.login-page .login-container .login-form .brandim .icon-im { + width: 19vw; + height: auto; + margin-right: 0px; +} + +.login-page .login-iframe { + height: 12vh; + position: absolute; + top: 85vh; + left: 0; + display: flex; + flex-direction: column; + -webkit-box-pack: center; + justify-content: center; + align-items: flex-start; + min-height: 12vh; + z-index: 2; + width: 18vw; + margin-left: 1vw; + background: transparent; +} +.login-page .login-iframe .login-iform { + display: flex; + flex-direction: column; + -webkit-box-align: center; + align-items: center; + position: absolute; + top: 0px; + width: 100%; + min-height: 12vh; + max-width: 100%; +} + +.login-page .login-iframe .login-iform .ifframe { + width: 100vw; + max-width: 100%; + height: 50vh; + max-height: 100%; + left: 0px; + position: absolute; + top: 0px; +} + +.login-page .login-bframe { + height: 45vh; + position: absolute; + top: 52vh; + left: 0; + display: flex; + flex-direction: column; + -webkit-box-pack: center; + justify-content: center; + align-items: flex-start; + min-height: 45vh; + z-index: 2; + width: 24vw; + margin-left: -2vw; + background: transparent; +} +.login-page .login-bframe .login-bform { + display: flex; + flex-direction: column; + -webkit-box-align: center; + align-items: center; + position: absolute; + top: 0px; + width: 100%; + min-height: 45vh; + max-width: 100%; +} + +.login-page .login-bframe .login-bform .ibframe { + width: 100vw; + max-width: 100%; + height: 50vh; + max-height: 100%; + left: 0px; + position: absolute; + top: 0px; +} + +/* size of logo displayed */ +.login-page .login-container .login-form .brand .icon-lg { + width: 19vw; + height: auto; + margin-right: 10px; +} + +.login-page .login-container .login-form .brand .icon { + width: 7vw; + height: auto; + margin-right: 10px; +} + +.login-page .login-container .login-form .brand .brand-text { + font-size: 1.2vw; + font-weight: 700; + font-family: TypoGraphica; +} + +.login-page .login-container .login-form .brand .brand-textlg { + font-size: 1.2vw; + font-weight: 700; + font-family: TypoGraphica; + margin-left: 2vw; +} + +.login-page .login-container .login-form .form-login { + width: 100%; + box-sizing: border-box; + padding: 20px 50px; +} + +.login-page .login-container .login-form .form-login .errorbox { + text-align: center; + color: var(--warning); + padding-bottom: 2rem; +} + +.login-page .login-container .login-form .form-login .input-group { + margin-bottom: 1.25rem; + position: relative; +} + +.login-page .login-container .login-form .form-login .input-group::before { + font-family: argon!important; + font-style: normal; + font-weight: 400; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + color: var(--default); + font-size: 1.5rem; + position: absolute; + z-index: 100; + left: 10px; + top: 10px; +} + +.login-page .login-container .login-form .form-login .input-group .border { + position: absolute; + width: 100%; + height: 1px; + bottom: 0; + border-bottom: 1px var(--primary) solid; + transform: scaleX(0); + transition: transform .3s; +} + +.login-page .login-container .login-form .form-login .input-group input { + font-size: 1rem; + line-height: 1.5em; + display: block; + width: 100%; + box-sizing: border-box; + transition: all .3s cubic-bezier(.68,-0.55,.265,1.55); + color: var(--default); + border: 0; + border-radius: 0; + border-bottom: 1px solid var(--white); + background-color: transparent; + background-clip: padding-box; + box-shadow: 0 3px 2px rgba(233,236,239,0.05); + outline: none; + margin: .825rem 0; + padding: .5rem .75rem .5rem 3rem; +} + +.login-page .login-container .login-form .form-login .input-group input:focus+.border { + transform: scaleX(1); +} + +.login-page .login-container .login-form .form-login .input-group .cbi-input-password { + margin-bottom: 2rem; + position: relative; +} + +.login-page .login-container .login-form .form-login .user-icon::before { + content: "\e971"; +} + +.login-page .login-container .login-form .form-login .pass-icon::before { + content: "\e910"; +} + +.login-page .login-container .login-form .cbi-button-apply { + width: 100%!important; + box-shadow: rgba(0,0,0,0.1) 0 0 50px 0; + font-weight: 600; + font-size: 15px; + color: var(--white); + text-align: center; + cursor: pointer; + min-height: 50px; + background-color: var(--primary)!important; + border-radius: 6px; + outline: none; + border-image: initial; + transition: all .3s!important; + letter-spacing: .8rem; + border-color: initial; + border-style: none; + border-width: initial; + margin: 30px 0px 20px; + padding: 10px 0px; +} + +.login-page .login-container .login-form .cbi-button-apply:hover,.login-page .login-container .login-form .cbi-button-apply :focus { + opacity: .9; +} + +.login-page .login-container footer { + box-sizing: border-box; + width: 100%; + text-align: center; + line-height: 1.6rem; + display: flex; + justify-content: space-evenly; + margin-top: auto; + z-index: 10; + color: var(--default); + position: absolute; + bottom: 0; + padding: 0px 0px 30px; +} + +.login-page .login-container footer .ftc { + position: absolute; + bottom: 30px; + width: 100%; +} + +footer { + font-size: .8rem; + overflow: hidden; + text-align: right; + white-space: nowrap; + color: #aaa; + padding: 1rem; +} + +footer>a { + text-decoration: none; + color: #aaa; +} + +small { + font-size: 90%; + line-height: 1.42857143; + white-space: normal; +} + +.main { + position: relative; + top: 0; + bottom: 0; + overflow-y: auto; + height: 100%; +} + +.main-left { + top: 0; + float: left; + width: calc(0% + 15rem); + height: 100%; + background-color: var(--menu-bg-color); + box-shadow: rgba(0,0,0,0.75) 0 0 15px -5px; + overflow-x: auto; + position: fixed; + z-index: 100; +} + +.main-left .sidenav-header { + text-align: center; + padding: 1.5rem; +} + +.main-left .sidenav-header .brand { + font-size: 1.8rem; + color: var(--primary); + font-family: TypoGraphica; + text-decoration: none; + text-align: center; + cursor: default; + vertical-align: text-bottom; + white-space: nowrap; +} + +.main-left::-webkit-scrollbar { + width: 5px; + height: 1px; +} + +.main-right { + float: right; + width: calc(100% - 15rem); + height: 100%; + transition: all .2s; +} + +.main-right>#maincontent { + position: relative; + z-index: 50; +} + +.pull-right { + float: right; +} + +.nowrap:not(.td) { + white-space: nowrap; +} + +[disabled="disabled"] { + pointer-events: none; +} + +header { + color: var(--header-color); + position: relative; + padding: 0; +} + +header.bg-primary { + background-color: var(--primary)!important; +} + +header::after { + content: ""; + position: absolute; + height: 2rem; + width: 100%; + background-color: var(--primary)!important; +} + +header .fill { + border-bottom: 0 solid rgba(255,255,255,0.08)!important; + padding: .8rem 0; +} + +header .fill .container { + height: 2rem; + padding: 0 1.25rem; +} + +header .fill .container .showSide { + display: none; + color: #fff; + font-size: 1.4rem; +} + +header .fill .container .brand { + font-size: 1.5rem; + color: #fff; + font-family: TypoGraphica; + text-decoration: none; + padding-left: 1rem; + cursor: default; + vertical-align: text-bottom; + display: none; +} + +header .fill .container .pull-right { + float: right; + margin-top: 0rem; + display: flex; +} + +header .fill .status { + position: absolute; + top: 25%; + right: 1.25rem; + float: right; +} + +header .fill .status span[data-indicator="poll-status"] { + display: block; + font-size: .8rem; + font-weight: 700; + white-space: nowrap; + text-decoration: none; + text-transform: uppercase; + text-shadow: none; + border-radius: 3px; + cursor: pointer; + transition: all .3s; + padding: .3rem .8rem; +} + +header .fill .status span[data-style="active"] { + color: #32325d!important; + background-color: #fff; +} + +header .fill .status span[data-style="inactive"] { + color: #FFF!important; + background-color: #32325d; +} + +#xhr_poll_status { + display: flex; + margin-left: .5rem; +} + +div[style="width:100%;height:300px;border:1px solid #000;background:#fff"] { + border: 0!important; +} + +.danger { + background-color: #ff7d60!important; +} + +.warning { + background-color: #f0e68c!important; +} + +.success { + background-color: #5cb85c!important; +} + +.notice { + background-color: #11cdef!important; + color: #fff; +} + +.error { + color: red; +} + +.alert,.alert-message { + font-weight: 700; + margin-bottom: 1em; + border: 0; + border-radius: .375rem!important; + background-color: #fff; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 rgba(0,0,0,0.12); + text-shadow: 1px 1px rgba(0,0,0,0.1); + padding: 1rem; +} + +.alert.error,.alert-message.error { + background-color: #ffd600; +} + +.alert h4,.alert-message h4 { + padding: 0 1.5rem .75rem 0; +} + +.alert-message>h4 { + font-size: 110%; + font-weight: 700; +} + +.alert-message>* { + margin: .5rem 0; +} + +.alert-message .btn { + padding: .3rem .6rem; +} + +.main .main-left { + transition: all .2s; +} + +.main .main-left .nav li { + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + padding: 0; +} + +.main .main-left .nav li a { + display: block; + color: var(--menu-color); +} + +.main .main-left .nav li.slide .slide-menu { + margin: 0 .5rem 0 2.5rem; + padding: 0 .5rem; +} + +.main .main-left .nav li.slide .slide-menu li { + position: relative; + border-radius: .375rem; + background: none; + list-style: none; + margin: 0; + padding: .5rem 0; +} + +.main .main-left .nav li.slide .slide-menu li a { + white-space: nowrap; + text-decoration: none; +} + +.main .main-left .nav li.slide .slide-menu li::after { + content: ""; + position: absolute; + left: 0; + bottom: 0; + width: 0; + height: 2px; + background-color: var(--primary); + transition: all .2s; +} + +.main .main-left .nav li.slide .slide-menu .active { + background: none; + color: var(--menu-color); +} + +.main .main-left .nav li.slide .slide-menu .active a { + color: var(--menu-color); +} + +.main .main-left .nav li.slide .slide-menu .active::after { + content: ""; + position: absolute; + left: 0; + bottom: 0; + width: 100%; + height: 2px; + background-color: var(--primary); + transition: all .2s; +} + +.main .main-left .nav li .menu::after { + position: absolute; + right: .5rem; + top: .8rem; + font-family: argon!important; + font-style: normal; + font-weight: 400; + font-variant: normal; + text-transform: none; + line-height: 1; + -moz-osx-font-smoothing: grayscale; + content: '\e90f'; + color: #ced4da; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + transition: all .3s; +} + +.main .main-left .nav li .menu[data-title=Status]:before { + content: "\e906"; + color: var(--primary); +} + +.main .main-left .nav li .menu[data-title=System]:before { + content: "\e90a"; + color: #fb6340; +} + +.main .main-left .nav li .menu[data-title=Services]:before { + content: "\e909"; + color: #11cdef; +} + +.main .main-left .nav li .menu[data-title=NAS]:before { + content: "\e90c"; + color: #f3a4b5; +} + +.main .main-left .nav li .menu[data-title=VPN]:before { + content: "\e90b"; + color: #8965e0; +} + +.main .main-left .nav li .menu[data-title=Network]:before { + content: "\e908"; + color: #8965e0; +} + +.main .main-left .nav li .menu[data-title=Bandwidth_Monitor]:before { + content: "\e90d"; + color: #2dce89; +} + +.main .main-left .nav li .menu[data-title=Docker]:before { + content: "\e911"; + color: #69F; +} + +.main .main-left .nav li .menu[data-title=Statistics]:before { + content: "\e913"; + color: #8965e0; +} + +.main .main-left .nav li .menu[data-title=Control]:before { + content: "\e912"; + color: var(--primary); +} + +.main .main-left .nav li .menu[data-title=Asterisk]:before { + content: "\e914"; + color: #fb6340; +} + +.main .main-left .nav li a[data-title=Logout]:before { + content: "\e907"; + color: #adb5bd; +} + +.lg { + margin: 0; + padding: 0!important; +} + +.logout { + display: block; + border-radius: .375rem; + text-decoration: none; + font-size: 1rem; + transition: all .2s; + position: relative; + margin: .8rem .5rem .1rem; + padding: .675rem 0 .675rem 2.5rem; +} + +.logout:before { + font-family: argon!important; + font-style: normal; + font-weight: 400; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + position: absolute; + left: .8rem; + padding-top: 3px; + transition: all .3s; + content: "\e907"; + color: #32325d!important; +} + +body[class*="node-"]>.main>.main-left>.nav>.slide>.menu::before { + transition: transform .1s ease-in-out; +} + +body[class*="node-"]>.main>.main-left>.nav>.slide>.menu.active::before { + transition: transform .2s ease-in-out; +} + +#maincontent>.container { + margin: 0 1.25rem 1rem; +} + +ul { + line-height: normal; +} + +h1 { + font-size: 2rem; + padding-bottom: 10px; + border-bottom: thin solid #eee; +} + +h2 { + font-size: 1.25rem; + letter-spacing: .1rem; + color: #32325d; + border-radius: .375rem; + background: #fff; + box-shadow: 0 4px 8px rgba(0,0,0,0.03); + margin: 0 0 1rem; + padding: 1rem 1.5rem; +} + +h3 { + font-size: 1.1rem; + line-height: 1; + display: block; + width: 100%; + color: var(--gray-dark); + border-radius: .375rem; + background: #fff; + margin: 0; + padding: .8755rem 1.5rem; +} + +h4 { + font-size: .7rem; + font-weight: 600; + color: #525f7f; + background-color: var(--lighter); + margin: 0; + padding: .75rem 1.5rem; +} + +h4 em { + padding: 0 .5rem; +} + +h5 { + font-size: 1rem; + padding-bottom: 10px; + margin: 2rem 0 0; +} + +.cbi-section,.cbi-section-error,#iptables,.Firewall form,#cbi-network>.cbi-section-node,#cbi-wireless>.cbi-section-node,#cbi-wireless>#wifi_assoclist_table,[data-tab-title],[data-page^="admin-system-admin"]:not(.node-main-login) .cbi-map:not(#cbi-dropbear),[data-page="admin-system-opkg"] #maincontent>.container { + font-family: inherit; + font-weight: 400; + font-style: normal; + line-height: normal; + min-width: inherit; + border: 0; + border-radius: .375rem; + background-color: #fff; + box-shadow: 0 0 1rem 0 rgba(136,152,170,0.15); + margin: 1.5rem 0; + padding: 0rem; +} + +.cbi-modal .cbi-section,.cbi-section .cbi-section { + box-shadow: none; + padding: 0; +} + +.cbi-modal .cbi-tabmenu { + margin-left: 0; +} + +.cbi-map-descr,.cbi-section-descr { + font-size: small; + line-height: 1.42857143; + padding: .5rem 1.5rem; +} + +.cbi-map-descr>abbr { + cursor: help; + text-decoration: underline; +} + +.cbi-section>legend { + display: none!important; +} + +fieldset>fieldset,.cbi-section>.cbi-section { + border: 0; + box-shadow: none; + margin: 0; + padding: 0; +} + +.cbi-section>h3:first-child,.panel-title { + font-size: 1.1rem; + line-height: 1; + display: block; + width: 100%; + color: var(--gray-dark); + margin: 0; + padding: .8755rem 1.5rem; +} + +table { + border-spacing: 0; + border-collapse: collapse; +} + +table,.table { + overflow-y: hidden; + width: 100%; + font-size: 90%; +} + +.table .table-titles th { + background-color: var(--lighter); +} + +.container>.cbi-section:first-of-type>.table[width="100%"]>.tr>.td { + padding: .6rem; +} + +.cbi-section-table-cell { + line-height: 1.1; + align-self: flex-end; + flex: 1 1 auto; +} + +tr>td,tr>th,.tr>.td,.tr>.th,.cbi-section-table-row::before,#cbi-wireless>#wifi_assoclist_table>.tr:nth-child(2) { + border-top: thin solid #ddd; + padding: 1.1em 1.5rem; +} + +#cbi-wireless .td,#cbi-network .tr:first-child>.td,.table[width="100%"]>.tr:first-child>.td,[data-page="admin-network-diagnostics"] .tr>.td,.tr.table-titles>.th,.tr.cbi-section-table-titles>.th { + border-top: 0!important; + background-color: #f6f9fc; + line-height: 1.3rem; + padding: 1.1em 1.5rem; +} + +.table[width="100%"]>.tr:first-child>.td { + margin: auto 0; +} + +.cbi-section-table-row { + margin-bottom: 1rem; + text-align: center!important; + background: #f4f4f4; +} + +.cbi-section-table-row:last-child { + margin-bottom: 0; +} + +.cbi-section-table-row>.cbi-value-field [data-dynlist]>input,.cbi-section-table-row>.cbi-value-field input.cbi-input-password { + width: calc(100% - 1.5rem); +} + +table table,.table .table,.cbi-value-field table,.cbi-value-field .table,td>table>tbody>tr>td,.td>.table>.tbody>.tr>.td,.cbi-value-field>table>tbody>tr>td,.cbi-value-field>.table>.tbody>.tr>.td { + border: 0; +} + +.btn,.cbi-button,.item::after { + font-size: .8rem; + display: inline-block; + width: auto!important; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + transition: all .2s ease-in-out; + text-align: center; + vertical-align: middle; + white-space: nowrap; + text-decoration: none; + text-transform: uppercase; + color: rgba(0,0,0,0.87); + border: 0; + border-radius: .2rem; + background-color: #f0f0f0; + background-image: none; + -webkit-appearance: none; + -ms-touch-action: manipulation; + touch-action: manipulation; + padding: .45rem .8rem; +} + +.cbi-button-up,.cbi-button-down { + font-size: 1.2rem; + display: inline-block; + min-width: 0; + color: transparent!important; + background: url(../icon/arrow.svg) no-repeat center; + background-size: 12px 20px; + padding: .2rem .3rem; +} + +.cbi-button-up { + transform: scaleY(-1); +} + +.cbi-button:not(select) { + -webkit-appearance: none!important; +} + +.btn:hover,.btn:focus,.btn:active,.cbi-button:hover,.cbi-button:focus,.cbi-button:active,.item:hover::after,.item:focus::after,.item:active::after,.cbi-page-actions .cbi-button-apply+.cbi-button-save:hover,.cbi-page-actions .cbi-button-apply+.cbi-button-save:focus,.cbi-page-actions .cbi-button-apply+.cbi-button-save:active { + text-decoration: none; + outline: 0; +} + +.btn:hover,.btn:focus,.cbi-button:hover,.cbi-button:focus,.item:hover::after,.item:focus::after { + box-shadow: 0 0 2px rgba(0,0,0,0.12),0 2px 2px rgba(0,0,0,0.2); +} + +.btn:active,.cbi-button:active,.item:active::after { + box-shadow: 0 10px 20px rgba(0,0,0,0.19),0 6px 6px rgba(0,0,0,0.23); +} + +.cbi-button-up:hover,.cbi-button-up:focus { + box-shadow: 0 0 2px rgba(0,0,0,0.12),0 -2px 2px rgba(0,0,0,0.2); +} + +.cbi-button-up:active { + box-shadow: 0 -10px 20px rgba(0,0,0,0.19),0 -6px 6px rgba(0,0,0,0.23); +} + +.btn:disabled,.cbi-button:disabled { + cursor: not-allowed; + pointer-events: none; + opacity: .5; + box-shadow: none; +} + +.alert-message [class="btn"],.modal div[class="btn"],.cbi-button-find,.cbi-button-link,.cbi-button-up,.cbi-button-down,.cbi-button-neutral,.cbi-button[name="zero"],.cbi-button[name="restart"],.cbi-button[onclick="hide_empty(this)"] { + font-weight: 700; + color: #fff; + border: thin solid #8898aa; + background-color: #8898aa; +} + +.btn.danger,.cbi-section-remove>.cbi-button,.cbi-button-remove,.cbi-button-reset,.cbi-button-negative,.cbi-button[value="Stop"],.cbi-button[value="Kill"],.cbi-button[onclick="reboot(this)"],.cbi-button-neutral[value="Restart"] { + font-weight: 400; + color: #fff; + border: thin solid var(--red); + background-color: var(--red); +} + +.btn[value="Dismiss"],.cbi-button[value="Terminate"],.cbi-button[value="Reset"],.cbi-button[value="Disabled"],.cbi-button[onclick^="iface_reconnect"],.cbi-button[onclick="handleReset(event)"],.cbi-button-neutral[value="Disable"] { + font-weight: 400; + color: #fff; + border: thin solid #eea236; + background-color: #f0ad4e; +} + +.cbi-button-success,.cbi-button-download,.cbi-button[name="backup"],.cbi-button[value="Download"],.cbi-button[value="Save mtdblock"] { + font-weight: 400; + color: #fff; + border: thin solid #4cae4c; + background-color: #5cb85c; +} + +.cbi-value-field .cbi-button-add { + font-weight: 700; + display: flex; + align-items: center; + margin: 4px 0 4px 3px; + padding: 1px 6px; +} + +.tabs { + background-color: #FFF; + border-radius: .375rem; + box-shadow: 0 4px 8px rgba(0,0,0,0.03); + white-space: nowrap; + overflow-x: auto; + margin: 0 0 1rem; + padding: 0 1rem; +} + +.tabs li[class~="active"],.tabs li:hover { + cursor: pointer; + border-bottom: .18751rem solid var(--primary); + color: var(--primary); + background-color: #dce1fe; + margin-bottom: 0; + border-radius: 0; +} + +.tabs li { + font-size: .875rem; + display: inline-block; + border-bottom: .18751rem solid rgba(0,0,0,0); + margin: 0 .2rem; + padding: .875rem 0; +} + +.tabs li:hover { + border-bottom: .18751rem solid var(--primary); +} + +.cbi-tabmenu { + color: #fff; + white-space: nowrap; + overflow-x: auto; + padding: .5rem 1rem 0; +} + +.cbi-tabmenu li { + background: #dce3e9; + display: inline-block; + font-size: .875rem; + border-top-left-radius: .25rem; + border-top-right-radius: .25rem; + border-bottom: .18751rem solid rgba(0,0,0,0); + margin: 0 .2rem; + padding: .5rem 0; +} + +.cbi-tabmenu li:hover { + cursor: pointer; + border-bottom: .18751rem solid var(--primary); + color: var(--primary); + background-color: #dce1fe; + margin-bottom: 0; +} + +.cbi-tabmenu li:hover a { + color: #525f7f; +} + +.cbi-tabmenu li[class~="cbi-tab"] { + border-bottom: .18751rem solid var(--primary); + color: var(--primary); + background-color: #dce1fe; + margin-bottom: 0; +} + +.cbi-tab-descr { + padding: .5rem 1.5rem; +} + +[data-tab-title] { + overflow: hidden; + height: 0; + opacity: 0; + margin: 0; + padding: 0rem!important; +} + +[data-tab-title] p { + margin-left: 1rem; + margin-bottom: 1rem; +} + +[data-tab-active="true"] { + overflow: visible; + height: auto; + opacity: 1; + transition: opacity .25s ease-in; + margin: inherit!important; +} + +.cbi-section-node-tabbed { + margin-top: 0; + border: 0 solid #d4d4d4; + border-radius: .375rem; + padding: 0; +} + +.cbi-value-field,.cbi-value-description { + line-height: 1.25; + display: table-cell; +} + +.cbi-value-field abbr,.cbi-value-description abbr { + color: var(--gray-dark); +} + +.cbi-value-description { + font-size: small; + opacity: .5; + padding: .5rem; +} + +.cbi-value-title { + display: table-cell; + float: left; + width: 23rem; + padding-top: .25rem; + padding-right: 2rem; + text-align: right; + word-wrap: break-word; +} + +.cbi-value { + display: inline-block; + width: 100%; + line-height: 2.4rem; + padding: .35rem 1rem .2rem; +} + +.cbi-value ul { + line-height: 1.25; +} + +.cbi-value-field .cbi-dropdown,.cbi-value-field .cbi-input-select,.cbi-value input[type="text"],.cbi-value input[type="password"] { + min-width: 18rem; +} + +.cbi-value input[type="password"] { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + margin-right: 0; +} + +.cbi-value input[type="password"]+.cbi-button-neutral { + height: 42px; + border-bottom-left-radius: 0; + border-top-left-radius: 0; + margin-left: 0; + border: 0; +} + +#cbi-firewall-zone .cbi-input-select,#cbi-network-switch_vlan .cbi-input-select { + min-width: 11rem; +} + +#cbi-network-switch_vlan .cbi-input-text { + max-width: 3rem; +} + +.cbi-input-invalid { + color: #f5365c; + border-bottom-color: #f5365c; +} + +.cbi-section-error { + font-weight: 700; + line-height: 1.42857143; + border: thin solid #f5365c; + border-radius: 3px; + background-color: #fce6e6; + margin: 18px; + padding: 6px; +} + +.cbi-section-error ul { + margin: 0 0 0 20px; +} + +.cbi-section-error ul li { + font-weight: 700; + color: #f5365c; +} + +.td[data-title]::before { + font-weight: 700; + display: none; + content: attr(data-title) ":\20"; + text-align: left; + white-space: nowrap; + padding: .25rem 0; +} + +.tr[data-title]::before,.tr.cbi-section-table-titles.named::before { + font-weight: 700; + display: table-cell; + align-self: center; + flex: 1 1 5%; + content: attr(data-title) "\20"; + text-align: center; + vertical-align: middle; + white-space: normal; + word-wrap: break-word; + padding: .25rem; +} + +.cbi-rowstyle-2 { + background-color: #eee; +} + +.cbi-rowstyle-2 .cbi-button-up,.cbi-rowstyle-2 .cbi-button-down,body:not(.Interfaces) .cbi-rowstyle-2:first-child { + background-color: #fff!important; +} + +.cbi-section-table .cbi-section-table-titles .cbi-section-table-cell { + width: auto!important; +} + +.td.cbi-section-actions { + text-align: right!important; + vertical-align: middle; +} + +.td.cbi-section-actions>* { + display: inline-flex; +} + +.td.cbi-section-actions>*>*,.td.cbi-section-actions>*>form>* { + display: flex; + align-items: center; + margin: 0 5px; +} + +.td.cbi-section-actions>*>form { + display: inline-flex; + margin: 0; +} + +.cbi-checkbox { + margin: 0 .25rem; +} + +.cbi-dynlist { + line-height: 1.3; + flex-direction: column; + min-height: 30px; + cursor: text; +} + +.cbi-dynlist>.item { + position: relative; + max-width: 25rem; + pointer-events: none; + color: #8898aa; + outline: 0; +} + +.cbi-dynlist[name="sshkeys"]>.item { + max-width: none; +} + +.cbi-dynlist>.item::after { + position: absolute; + width: 2.2rem!important; + height: calc(100% - .5rem - 2px); + right: 0; + bottom: 0; + content: "\00D7"; + pointer-events: auto; + background-color: var(--red); + font-weight: 400; + font-size: 1.2rem; + display: flex; + align-items: center; + justify-content: center; + line-height: 1.5rem; + color: #fff; + border: 1px solid #f5365c; + border-radius: .25rem; + outline: 0; + background-image: none; + box-shadow: none; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin: .25rem .1rem .25rem 0; + padding: 0; +} + +.cbi-dynlist>.item>span { + white-space: normal; + word-break: break-word; + line-height: 1.5rem; + color: #8898aa; + border: 1px solid #dee2e6; + border-radius: .25rem; + outline: 0; + background-image: none; + box-shadow: none; + display: block; + transition: box-shadow .15s ease; + box-sizing: border-box; + min-width: 15rem; + margin: .25rem .1rem; + padding: .5rem; +} + +.cbi-dynlist>.add-item { + display: inline-flex; + align-items: center; + width: 100%; + min-width: 16rem; +} + +.cbi-dynlist>.add-item input { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + margin-right: 0; + border-right: none; +} + +.cbi-dynlist>.add-item .cbi-button-add { + font-weight: 400; + font-size: 1.2rem; + display: flex; + align-items: center; + line-height: 1.5rem; + color: #fff; + border: 1px solid var(--primary); + border-radius: .25rem; + outline: 0; + background-image: none; + box-shadow: none; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin: .25rem .1rem .25rem 0; + padding: .5rem .75rem; +} + +.cbi-dynlist>.add-item:not([ondrop])>input { + overflow: hidden; + width: 100%; + min-width: 15rem; + white-space: nowrap; + text-overflow: ellipsis; +} + +.cbi-dynlist>.add-item[ondrop]>input { + min-width: 13rem; +} + +.cbi-dynlist,.cbi-dropdown { + position: relative; + display: inline-flex; + padding: .2rem; +} + +.cbi-dropdown[placeholder*="select"] { + max-width: 25rem; + height: auto; + margin-top: -3px; +} + +.cbi-dropdown>ul { + display: flex; + overflow-x: hidden; + overflow-y: auto; + width: 100%; + list-style: none; + outline: 0; + margin: 0!important; + padding: 0; +} + +.cbi-dropdown>.open { + flex-basis: 15px; +} + +.cbi-dropdown>.open,.cbi-dropdown>.more { + font-size: 1rem; + font-weight: 900; + line-height: 2; + display: flex; + flex-direction: column; + flex-grow: 0; + flex-shrink: 0; + justify-content: center; + cursor: default; + text-align: center; + outline: 0; + padding: 0 .25em; +} + +.cbi-dropdown>.more,.cbi-dropdown>ul>li[placeholder] { + font-weight: 700; + display: none; + color: #777; + text-shadow: 1px 1px 0 #fff; +} + +.cbi-dropdown>ul>li { + display: none; + overflow: hidden; + align-items: center; + align-self: center; + flex-grow: 1; + flex-shrink: 1; + min-height: 20px; + white-space: nowrap; + text-overflow: ellipsis; + padding: .25em; +} + +.cbi-dropdown>ul>li[display]:not([display="0"]) { + border-left: thin solid #ccc; +} + +.cbi-dropdown[empty]>ul { + max-width: 1px; +} + +.cbi-dropdown>ul>li>form { + display: none; + pointer-events: none; + margin: 0; + padding: 0; +} + +.cbi-dropdown>ul>li img { + margin-right: .25em; + vertical-align: middle; +} + +.cbi-dropdown>ul>li>form>input[type="checkbox"] { + height: auto; + margin: 0; +} + +.cbi-dropdown>ul>li input[type="text"] { + height: 20px; +} + +.cbi-dropdown[open]>ul.dropdown { + position: absolute; + z-index: 1100; + display: block; + width: auto; + min-width: 100%; + max-width: none; + max-height: 200px!important; + border: 0 solid #918e8c; + background: #FFF; + box-shadow: 0 0 4px #918e8c; + border-bottom-left-radius: .35rem; + border-bottom-right-radius: .35rem; + color: var(--main-menu-color); + margin-left: -0.2rem!important; +} + +.cbi-dropdown[open]>ul.dropdown li { + color: #000; +} + +.cbi-dropdown>ul>li[display],.cbi-dropdown[open]>ul.preview,.cbi-dropdown[open]>ul.dropdown>li,.cbi-dropdown[multiple]>ul>li>label,.cbi-dropdown[multiple][open]>ul.dropdown>li,.cbi-dropdown[multiple][more]>.more,.cbi-dropdown[multiple][empty]>.more { + display: flex; + align-items: center; + flex-grow: 1; +} + +.cbi-dropdown[open]>ul.dropdown>li { + border-bottom: thin solid #ccc; + padding: .5rem .8rem; +} + +.cbi-dropdown[open]>ul.dropdown>li[selected] { + background: #dce1fe; +} + +.cbi-dropdown[open]>ul.dropdown>li.focus { + background: #dce1fe; + outline: none; +} + +.cbi-dropdown[open]>ul.dropdown>li:last-child { + margin-bottom: 0; + border-bottom: 0; +} + +.cbi-dropdown[open]>ul.dropdown>li[unselectable] { + opacity: .7; +} + +.cbi-dropdown[disabled] { + pointer-events: none; + opacity: .6; +} + +.cbi-dropdown[open] .zonebadge { + width: auto; +} + +.cbi-progressbar { + position: relative; + min-width: 170px; + height: 20px; + border: thin solid #999; + background: #eee; + border-radius: .2rem; + overflow: hidden; + margin: 6px 0; +} + +.cbi-progressbar>div { + width: 0; + height: 100%; + transition: width .25s ease-in; + background: var(--bar-bg); +} + +.cbi-progressbar::after { + font-family: monospace; + font-size: 1em; + font-weight: 700; + font-size-adjust: .38; + line-height: normal; + position: absolute; + top: 2px; + right: 0; + bottom: 2px; + left: 0; + overflow: hidden; + content: attr(title); + text-align: center; + white-space: pre; + text-overflow: ellipsis; +} + +#modal_overlay { + position: fixed; + z-index: 900; + top: 0; + right: 10000px; + bottom: 0; + left: -10000px; + overflow-y: scroll; + transition: opacity .125s ease-in; + opacity: 0; + background: rgba(0,0,0,0.7); + -webkit-overflow-scrolling: touch; +} + +.modal { + display: flex; + align-items: center; + flex-wrap: wrap; + width: 90%; + min-width: 270px; + max-width: 600px; + min-height: 32px; + border-radius: 3px!important; + background: #fff; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 rgba(0,0,0,0.12); + margin: 5em auto; + padding: 1em; +} + +.modal>* { + line-height: normal; + flex-basis: 100%; + margin-bottom: .5em; + max-width: 100%; +} + +.modal>pre,.modal>textarea { + font-size: 1rem; + font-size-adjust: .35; + overflow: auto; + margin-bottom: .5em; + cursor: auto; + white-space: pre-wrap; + color: #eee; + outline: 0; + background-color: #101010; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 rgba(0,0,0,0.12); + padding: 8.5px; +} + +.modal>h4 { + margin: .5em 0; +} + +.modal ul { + margin-left: 2.2em; +} + +.modal li { + list-style-type: square; + color: gray; +} + +.modal p { + word-break: break-word; +} + +.modal .label { + font-size: .6rem; + font-weight: 400; + cursor: default; + border-radius: 0; + padding: .1rem .3rem 0; +} + +.modal .label.warning { + background-color: #f0ad4e!important; +} + +.modal .btn { + padding: .45rem .8rem; +} + +.modal.cbi-modal { + max-width: 90%; + max-height: none; +} + +body.modal-overlay-active { + overflow: hidden; + height: 100vh; +} + +body.modal-overlay-active #modal_overlay { + right: 0; + left: 0; + opacity: 1; +} + +.spinning { + position: relative; + padding-left: 32px!important; +} + +.spinning::before { + position: absolute; + top: 0; + bottom: 0; + left: .2em; + width: 32px; + content: ""; + background: url(/luci-static/resources/icons/loading.gif) no-repeat center; + background-size: 16px; +} + +.left,.left::before { + text-align: left!important; +} + +.right,.right::before { + text-align: right!important; +} + +.top { + align-self: flex-start!important; + vertical-align: top!important; +} + +.bottom { + align-self: flex-end!important; + vertical-align: bottom!important; +} + +.inline { + display: inline; +} + +.cbi-page-actions { + padding-top: 1rem; + text-align: right; +} + +.cbi-page-actions>form[method="post"] { + display: inline-block; +} + +.th[data-type="button"],.td[data-type="button"],.th[data-type="fvalue"],.td[data-type="fvalue"] { + flex: 1 1 2em; + text-align: center; +} + +.ifacebadge { + display: inline-flex; + border-bottom: thin solid #ccc; + background: #eee; + box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05); + padding: .5rem .8rem; +} + +td>.ifacebadge,.td>.ifacebadge { + font-size: .8rem; + background-color: #f0f0f0; +} + +.ifacebadge>em,.ifacebadge>img { + display: inline-block; + align-self: flex-start; + margin: 0 .2rem; +} + +.ifacebadge>img+img { + margin: 0 .2rem 0 0; +} + +.network-status-table .ifacebox { + flex-grow: 1; + margin: .5em; +} + +.network-status-table .ifacebox-body { + display: flex; + flex-direction: column; + height: 100%; +} + +.network-status-table .ifacebox-body>span { + flex: 10 10 auto; + height: 100%; +} + +.network-status-table .ifacebox-body .ifacebadge { + align-items: center; + flex: 1 1 auto; + min-width: 220px; + background-color: #fff; + margin: .5em 0 0; + padding: .5em; +} + +.cbi-input-textarea { + font-family: monospace; + width: 100%; + font-size: .875rem; + min-height: 14rem; + color: #000; + padding: .8rem; +} + +#syslog { + font-size: small; + line-height: 1.25; + overflow-y: hidden; + width: 100%; + min-height: 15rem; + resize: none; + color: #242424; + border: 0; + border-radius: .375rem; + background-color: #FFF; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 rgba(0,0,0,0.12); + padding: 1rem; +} + +#syslog:focus { + outline: 0; +} + +.uci-change-list { + font-family: monospace; +} + +.uci-change-list ins,.uci-change-legend-label ins { + display: block; + text-decoration: none; + border: thin solid #0f0; + background-color: #cfc; + padding: 2px; +} + +.uci-change-list del,.uci-change-legend-label del { + font-style: normal; + display: block; + text-decoration: none; + border: thin solid red; + background-color: #fcc; + padding: 2px; +} + +.uci-change-list var,.uci-change-legend-label var { + font-style: normal; + display: block; + text-decoration: none; + border: thin solid #ccc; + background-color: #eee; + padding: 2px; +} + +.uci-change-list var ins,.uci-change-list var del { + font-style: normal; + white-space: pre; + border: 0; + padding: 0; +} + +.uci-change-legend { + padding: 5px; +} + +.uci-change-legend-label { + float: left; + width: 150px; +} + +.uci-change-legend-label>ins,.uci-change-legend-label>del,.uci-change-legend-label>var { + display: block; + float: left; + width: 10px; + height: 10px; + margin-right: 4px; +} + +.uci-change-legend-label var ins,.uci-change-legend-label var del { + line-height: .4; + border: 0; +} + +#iwsvg,#iwsvg2,#bwsvg { + border: thin solid #d4d4d4!important; +} + +#iwsvg,[data-page="admin-status-realtime-bandwidth"] #bwsvg { + border-top: 0!important; +} + +.ifacebox { + line-height: 1.25; + display: inline-flex; + flex-direction: column; + min-width: 100px; + border-bottom: thin solid #ccc; + background-color: #f9f9f9; + box-shadow: inset 0 1px 0 rgba(255,255,255,0.4),0 1px 2px rgba(0,0,0,0.2); +} + +.ifacebox-head { + background: #eee; + padding: .25em; +} + +.ifacebox-head.active { + background: var(--primary); +} + +.ifacebox-head.active * { + color: var(--white); +} + +.ifacebox-body { + line-height: 1.6em; + padding: .5em 1rem; +} + +.zonebadge { + display: inline-block; + padding: .2rem .5rem; +} + +.zonebadge .ifacebadge { + border: thin solid #6c6c6c; + margin: .1rem .2rem; + padding: .2rem .3rem; +} + +.zonebadge>input[type="text"] { + min-width: 10rem; + margin-top: .3rem; + padding: .16rem 1rem; +} + +.zonebadge>em,.zonebadge>strong { + display: inline-block; + margin: 0 .2rem; +} + +.cbi-value-field .cbi-input-checkbox,.cbi-value-field .cbi-input-radio { + margin-top: .1rem; +} + +.cbi-value-field>ul>li { + display: flex; +} + +.cbi-value-field>ul>li .ifacebadge { + margin-top: -0.5rem; + margin-left: .4rem; + background-color: #eee; +} + +.cbi-section-table-row>.cbi-value-field .cbi-dropdown { + min-width: 7rem; +} + +.cbi-section-create { + display: inline-flex; + align-items: center; + margin: .25rem 0 .25rem 1rem; +} + +.cbi-section-create>* { + margin: .5rem; +} + +div.cbi-value var,td.cbi-value-field var,.td.cbi-value-field var { + font-style: italic; + color: #0069d6; +} + +.cbi-optionals { + border-top: thin solid #ccc; + padding: 1rem 1rem 0; +} + +.cbi-dropdown-container { + position: relative; +} + +.cbi-tooltip-container,span[data-tooltip],span[data-tooltip] .label { + cursor: help!important; +} + +.cbi-tooltip { + position: absolute; + z-index: 1000; + left: -1000px; + transition: opacity .25s ease-out; + white-space: pre; + pointer-events: none; + opacity: 0; + border-radius: 3px; + background: #fff; + box-shadow: 0 0 2px #444; + padding: 2px 5px; +} + +.cbi-tooltip-container:hover .cbi-tooltip { + left: auto; + transition: opacity .25s ease-in; + opacity: 1; +} + +.zonebadge .cbi-tooltip { + background: inherit; + margin: -1.5rem 0 0 -0.5rem; + padding: .25rem; +} + +.zonebadge-empty { + color: #404040; + background: repeating-linear-gradient(45deg,rgba(204,204,204,0.5),rgba(204,204,204,0.5) 5px,rgba(255,255,255,0.5) 5px,rgba(255,255,255,0.5) 10px); +} + +.zone-forwards { + display: flex; + min-width: 10rem; +} + +.zone-forwards>* { + flex: 1 1 45%; +} + +.zone-forwards>span { + flex-basis: 10%; + text-align: center; + padding: 0 .25rem; +} + +.zone-forwards .zone-src,.zone-forwards .zone-dest { + display: flex; + flex-direction: column; +} + +.label { + font-size: .8rem; + font-weight: 700; + white-space: nowrap; + text-decoration: none; + text-transform: uppercase; + color: #fff!important; + border-radius: 3px; + background-color: #bfbfbf; + text-shadow: none; + padding: .3rem .8rem; +} + +label>input[type="checkbox"],label>input[type="radio"] { + position: relative; + top: .4rem; + right: .2rem; + vertical-align: bottom; + margin: 0; +} + +label[data-index][data-depends] { + padding-right: 2em; +} + +.darkMask { + position: fixed; + z-index: 99; + display: none; + width: 100%; + height: 100%; + content: ""; + top: 0; + background-color: rgba(0,0,0,0.56); +} + +#diag-rc-output>pre,#command-rc-output>pre,[data-page="admin-services-wol"] .notice code { + font-size: 1.2rem; + font-size-adjust: .35; + line-height: normal; + display: block; + overflow-y: hidden; + width: 100%; + white-space: pre; + color: #eee; + background-color: #101010; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 rgba(0,0,0,0.12); + padding: 8.5px; +} + +[data-page="admin-network-diagnostics"] .table { + box-shadow: none; +} + +input[name="ping"],input[name="traceroute"],input[name="nslookup"] { + width: 80%; +} + +.node-status-overview>.main fieldset:nth-child(4) .td:nth-child(2),.node-status-processes>.main .table .tr .td:nth-child(3) { + white-space: normal; +} + +[data-page="admin-system-reboot"] .cbi-button { + background: #fb6340!important; +} + +[data-page="admin-system-reboot"] p>span { + position: relative; + top: .1rem; + left: 1rem; +} + +[data-page="admin-vpn-passwall"] h4 { + background: transparent; +} + +#cbi-samba [data-tab="template"] .cbi-value-title { + width: auto; + padding-bottom: .6rem; +} + +.controls { + margin: .5em 1rem 1em!important; +} + +.controls>*>.btn:not([aria-label$="page"]) { + flex-grow: initial!important; + margin-top: .25rem; +} + +.controls>#pager>.btn[aria-label$="page"] { + font-size: 1.4rem; + font-weight: 700; +} + +.controls>*>label { + margin-bottom: .2rem; +} + +[data-page="admin-system-opkg"] div.btn { + line-height: 3; + display: inline; + padding: .3rem .6rem; +} + +[data-page^="admin-system-admin"]:not(.node-main-login) .cbi-map:not(#cbi-dropbear),[data-page="admin-system-opkg"] #maincontent>.container { + margin-top: 2rem; + padding-top: .1rem; +} + +[data-page="admin-system-opkg"] #maincontent>.container { + margin: 0 1.25rem 1rem; +} + +.td.version,.td.size { + white-space: normal!important; + word-break: break-word; +} + +[data-page="admin-system-crontab"] #view p { + margin-bottom: 1rem; +} + +[data-page="admin-system-flash"] .cbi-map-tabbed { + border-radius: .375rem; +} + +[data-page="admin-system-flash"] legend { + display: block!important; + font-size: 1.2rem; + width: 100%; + border-bottom: 1px solid rgba(0,0,0,0.05); + line-height: 1.5; + margin-bottom: 0rem; + letter-spacing: .1rem; + color: #32325d; + font-weight: 700; + padding: 1rem 0 1rem 1.5rem; +} + +[data-page="admin-system-flash"] .cbi-section-descr { + font-weight: 600; + color: #525f7f; + padding: 1rem 0 1rem 1.5rem; +} + +[data-page="admin-system-flash"] .modal label>input[type="checkbox"] { + top: -0.35rem; +} + +[data-page="admin-system-flash"] .modal .btn { + white-space: normal!important; +} + +#cbi-wireless>#wifi_assoclist_table>.tr { + box-shadow: inset 1px -1px 0 #ddd,inset -1px -1px 0 #ddd; +} + +#cbi-wireless>#wifi_assoclist_table>.tr.placeholder>.td { + right: 33px; + bottom: 33px; + left: 33px; + border-top: thin solid #ddd!important; +} + +#cbi-wireless>#wifi_assoclist_table>.tr.table-titles { + box-shadow: inset 1px 0 0 #ddd,inset -1px 0 0 #ddd; +} + +#cbi-wireless>#wifi_assoclist_table>.tr.table-titles>.th { + border-bottom: thin solid #ddd; + box-shadow: 0 -1px 0 0 #ddd; +} + +#wifi_assoclist_table>.tr>.td[data-title="RX Rate / TX Rate"] { + width: 23rem; +} + +[data-page="admin-network-dhcp"] [data-tab-active="true"] { + padding: 1rem 0!important; +} + +#iptables { + margin: 0; +} + +.Firewall form { + box-shadow: none; + margin: 2rem 2rem 0 0; + padding: 0; +} + +#cbi-firewall-redirect table *,#cbi-network-switch_vlan table *,#cbi-firewall-zone table * { + font-size: small; +} + +#cbi-firewall-redirect table input[type="text"],#cbi-network-switch_vlan table input[type="text"],#cbi-firewall-zone table input[type="text"] { + width: 5rem; +} + +#cbi-firewall-redirect table select,#cbi-network-switch_vlan table select,#cbi-firewall-zone table select { + min-width: 3.5rem; +} + +#cbi-network-switch_vlan .th,#cbi-network-switch_vlan .td { + flex-basis: 12%; +} + +[data-page="admin-network-firewall-custom"] #view p,[data-page="admin-status-routes"] #view p { + margin-bottom: 1rem; + padding: 0 1.5rem; +} + +[data-page="admin-network-firewall-custom"] #view p textarea,[data-page="admin-status-routes"] #view p textarea { + border-radius: .375rem; + padding: 1rem; +} + +#applyreboot-container { + margin: 2rem; +} + +#applyreboot-section { + line-height: 300%; + margin: 2rem; +} + +.OpenVPN a { + line-height: initial!important; +} + +.commandbox { + width: 24%!important; + border-bottom: thin solid #ccc; + background: #eee; + box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05); + margin: 10px 0 0 10px!important; + padding: .5rem 1rem; +} + +.commandbox h3 { + line-height: normal!important; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + margin: 6px 0!important; +} + +.commandbox div { + left: auto!important; +} + +.commandbox code { + position: absolute; + overflow: hidden; + max-width: 60%; + margin-left: 4px; + white-space: nowrap; + text-overflow: ellipsis; + padding: 2px 3px; +} + +.commandbox code:hover { + overflow-y: auto; + max-height: 50px; + white-space: normal; +} + +.commandbox p:first-of-type { + margin-top: -6px; +} + +.commandbox p:nth-of-type(2) { + margin-top: 2px; +} + +#command-rc-output .alert-message { + line-height: 1.42857143; + position: absolute; + top: 40px; + right: 32px; + max-width: 40%; + animation: anim-fade-in 1.5s forwards; + word-break: break-word; + opacity: 0; + margin: 0; +} + +input[type="checkbox"] { + appearance: none!important; + -webkit-appearance: none!important; + border: 1px solid #dee2e6; + width: 16px!important; + height: 16px!important; + cursor: pointer; + transition: all .2s; + margin: 1rem 0 0; + padding: 0; +} + +input[type="checkbox"]:checked { + border: 1px solid var(--primary); + background-image: url('data:image/svg+xml,%3csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 8 8\'%3e%3cpath fill=\'%23fff\' d=\'M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z\'/%3e%3c/svg%3e')!important; + background-color: var(--primary); + background-size: 70%; + background-repeat: no-repeat; + background-position: center; +} + +.fb-container .cbi-button { + height: auto!important; +} + +#cbi-usb_printer-printer em { + display: block; + text-align: center; + padding: 1rem; +} + +pre.command-output { + padding: 1.5rem; +} + +[data-page="admin-nlbw-display"] .cbi-section[data-tab="export"] { + padding: 1.5rem!important; +} + +[data-page="admin-status-iptables"] .right { + margin-bottom: 0!important; +} + +.table[width="100%"],.th[width="100%"],.td[width="100%"],header,.main,.main .main-left .nav li.slide .slide-menu li:hover::after,.main .main-left .nav li.slide .slide-menu .active:hover::after,.cbi-section-table-row>.cbi-value-field .cbi-dropdown,.cbi-section-table-row>.cbi-value-field .cbi-input-select,.cbi-section-table-row>.cbi-value-field .cbi-input-text,.cbi-section-table-row>.cbi-value-field .cbi-input-password,.cbi-dropdown[open]>ul.dropdown>li>input.create-item-input:first-child:last-child,.cbi-dropdown .zonebadge,#cbi-firewall-zone .td,#cbi-network-switch_vlan .td { + width: 100%; +} + +.cbi-dropdown,select[multiple="multiple"],.alert .btn,.alert-message .btn { + height: auto; +} + +.login-page .login-container .login-form .brand:hover,header .fill .container .showSide:hover,.a-to-btn { + text-decoration: none; +} + +.login-page .login-container footer .luci-link,.cbi-dropdown[empty]>ul>li,.cbi-dropdown[optional][open]>ul.dropdown>li[placeholder],.cbi-dropdown[multiple][open]>ul.dropdown>li>form,#cbi-samba [data-tab="template"] .cbi-value-field,#cbi-firewall-zone .table,#cbi-network-switch_vlan .table { + display: block; +} + +.main-left::-webkit-scrollbar-thumb,.tabs::-webkit-scrollbar-thumb,.cbi-tabmenu::-webkit-scrollbar-thumb { + background-color: #f6f9fc; +} + +.main-left::-webkit-scrollbar-track,.tabs::-webkit-scrollbar-track,.cbi-tabmenu::-webkit-scrollbar-track { + background-color: #fff; +} + +.pull-left,.cbi-page-actions .cbi-button-link:first-child { + float: left; +} + +#xhr_poll_status *,.cbi-button-apply>ul.preview li,.cbi-button-apply>ul:first-child li { + color: #fff; +} + +.container .alert,.container .alert-message,.cbi-map-descr+fieldset { + margin-top: 1rem; +} + +.main .main-left .nav,.cbi-value-field>ul>li>label { + margin-top: .5rem; +} + +.main .main-left .nav>li>a:first-child,.main .main-left .nav li .menu { + border-radius: .375rem; + cursor: default; + display: block; + font-size: 1rem; + position: relative; + text-decoration: none; + transition: all .2s; + margin: .1rem .5rem; + padding: .675rem 0 .675rem 2.5rem; +} + +.main .main-left .nav>li>a:first-child.active,.main .main-left .nav li .menu.active { + background: var(--primary); + color: #fff; +} + +.main .main-left .nav>li>a:first-child.active::before,.main .main-left .nav>li>a:first-child:hover::before,.main .main-left .nav li .menu.active::before,.main .main-left .nav li .menu:hover::before { + color: #fff!important; +} + +.main .main-left .nav>li>a:first-child.active::after,.main .main-left .nav li .menu.active::after { + color: #fff!important; + transform: rotate(90deg); +} + +.main .main-left .nav>li>a:first-child:hover,.main .main-left .nav li .menu:hover { + background: var(--primary); + color: #fff; + cursor: pointer; +} + +.main .main-left .nav>li>a:first-child::before,.main .main-left .nav li .menu::before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + color: var(--primary); + content: "\e915"; + font-family: argon!important; + font-style: normal; + font-variant: normal; + font-weight: 400; + left: .8rem; + line-height: 1; + padding-top: 3px; + position: absolute; + text-transform: none; + transition: all .3s; +} + +.main .main-left .nav li.slide,[data-page="admin-system-flash"] .cbi-value,[data-page="admin-network-dhcp"] .cbi-value { + padding: 0; +} + +.main .main-left .nav li.slide ul,.main>.main-left[style*="overflow: hidden"]>.nav>.slide>.menu::before,.tr.placeholder .td[data-title]::before,.cbi-dropdown>ul.preview,.cbi-button-apply>ul.preview,.cbi-dropdown>ul>li .hide-close,.cbi-dropdown[open]>ul.dropdown>li .hide-open,.hidden,.showSide,[data-page^="admin-system-commands"] .panel-title,[data-page^="command-cfg"] .mobile-hide,[data-page^="command-cfg"] .showSide { + display: none; +} + +.main .main-left .nav li.slide:hover,.main .main-left .nav li.slide .slide-menu li:hover,.main .main-left .nav li.slide .slide-menu .active:hover { + background: none; +} + +.cbi-section>h3:first-child,.cbi-section>h4:first-child,.cbi-section>p:first-child,[data-tab-title]>h3:first-child,[data-tab-title]>h4:first-child,[data-tab-title]>p:first-child,.cbi-section p { + padding: 1rem; +} + +table>tbody>tr>td,table>tbody>tr>th,table>tfoot>tr>td,table>tfoot>tr>th,table>thead>tr>td,table>thead>tr>th,.table>.tbody>.tr>.td,.table>.tbody>.tr>.th,.table>.tfoot>.tr>.td,.table>.tfoot>.tr>.th,.table>.thead>.tr>.td,.table>.thead>.tr>.th,.table>.tr>.td.cbi-value-field,.table>.tr>.th.cbi-section-table-cell,.uci-change-list var,.uci-change-list del,.uci-change-list ins,.cbi-section-remove { + padding: .5rem; +} + +.cbi-section-table-row .td,.center,.center::before { + text-align: center!important; +} + +div>table>tbody>tr:nth-of-type(2n),div>.table>.tr:nth-of-type(2n),.cbi-section .cbi-section-remove:nth-of-type(2n),.container>.cbi-section .cbi-section-node:nth-of-type(2n),.cbi-section[id] .cbi-section-remove:nth-of-type(4n+3),.cbi-section[id] .cbi-section-node:nth-of-type(4n+4),.cbi-tabcontainer>.cbi-value:nth-of-type(2n),.cbi-rowstyle-1 { + background-color: #f9f9f9; +} + +.btn.primary,.cbi-page-actions .cbi-button-save,.cbi-page-actions .cbi-button-apply+.cbi-button-save,.cbi-button-add,.cbi-button-save,.cbi-button-positive,.cbi-button-link,.cbi-button[value="Enable"],.cbi-button[value="Scan"],.cbi-button[value^="Back"],.cbi-button-neutral[onclick="handleConfig(event)"],.cbi-page-actions .cbi-button-apply,.cbi-section-actions .cbi-button-edit,.cbi-button-edit,.cbi-button-apply,.cbi-button-reload,.cbi-button-action,.cbi-button[value="Submit"],.cbi-button[value="Upload"],.cbi-button[value$="Apply"],.cbi-button[onclick="addKey(event)"] { + background-color: var(--primary); + border: thin solid var(--primary); + color: #fff!important; + font-weight: 400; +} + +.tabs::-webkit-scrollbar,.cbi-tabmenu::-webkit-scrollbar { + height: 5px; + width: 1px; +} + +.tabs li[class~="active"] a,.tabs li:hover a,.cbi-tabmenu li[class~="cbi-tab"] a { + color: var(--primary); +} + +.tabs li a,.cbi-tabmenu li a { + color: #404040; + text-decoration: none; + padding: .5rem .8rem; +} + +.cbi-dropdown>ul>li .hide-open,.cbi-dropdown[open]>ul.dropdown>li .hide-close { + display: initial; +} + +.cbi-dropdown[open]>ul.dropdown>li label,.cbi-image-button { + margin-left: .5rem; +} + +.network-status-table,.network-status-table .ifacebox-body>div { + display: flex; + flex-wrap: wrap; +} + +[data-page="admin-system-reboot"] p,[data-page="admin-nlbw-backup"] form { + padding-left: 1.5rem; +} + +[data-page="admin-system-admin"] .cbi-map h2,[data-page="admin-system-admin-password"] .cbi-map h2,[data-page="admin-system-admin"] .cbi-map .cbi-map-descr,[data-page="admin-system-admin-password"] .cbi-map .cbi-map-descr,[data-page="admin-system-opkg"] h2 { + color: var(--gray-dark); + margin-left: 0; +} + +.cbi-tabmenu+.cbi-section,[data-page="admin-system-flash"] .cbi-section .cbi-section { + margin-top: 0; +} + +@keyframes anim-fade-in { + 100% { + opacity: 1; + } +} + +@media all and (-ms-high-contrast:none) { + .main>.main-left>.nav>.slide>.menu::before { + top: 30.25%; + } + + .main>.main-left>.nav>li:last-child::before { + top: 20%; + } + + .showSide::before { + top: -12px; + } +} + +@media screen and (max-width:1600px) { + header>.fill>.container>#logo { + margin: 0 2.5rem 0 .5rem; + } + + .main-left { + width: calc(0% + 13rem); + } + + .main-right { + width: calc(100% - 13rem); + } + + .btn:not(button),.cbi-button { + font-size: .8rem; + } + + .label { + padding: .2rem .6rem; + } + + .cbi-value-title { + width: 15rem; + padding-right: .6rem; + } + + .cbi-value-field .cbi-dropdown,.cbi-value-field .cbi-input-select,.cbi-value input[type="text"],.cbi-value input[type="password"] { + min-width: 18rem; + } + + #cbi-firewall-zone .cbi-input-select { + min-width: 9rem; + } + + .cbi-input-textarea { + font-size: small; + } + + .node-admin-status>.main fieldset li>a { + padding: .3rem .6rem; + } +} + +@media screen and (max-width:1366px) { + header>.fill>.container { + cursor: default; + } + + .main-left { + width: calc(0% + 13rem); + } + + .main-right { + width: calc(100% - 13rem); + } + + .tabs>li>a,.cbi-tabmenu>li>a { + padding: .2rem .8rem; + } + + .panel-title { + font-size: 1.1rem; + padding-bottom: 1rem; + } + + table { + font-size: .7rem!important; + width: 100%!important; + } + + .table .cbi-input-text { + width: 100%; + } + + .cbi-value-field .cbi-dropdown,.cbi-value-field .cbi-input-select,.cbi-value input[type="text"],.cbi-value input[type="password"] { + min-width: 16rem; + } + + #cbi-firewall-zone .cbi-input-select { + min-width: 4rem; + } + + .main>.main-left>.nav>li,.main>.main-left>.nav>li>a,.main .main-left .nav>li>a:first-child,.main>.main-left>.nav>.slide>.menu,.main>.main-left>.nav>li>[data-title="Logout"] { + font-size: .9rem; + } + + .main>.main-left>.nav>.slide>.slide-menu>li>a { + font-size: .7rem; + } + + #modal_overlay { + top: 0rem; + } + + [data-page="admin-network-firewall-forwards"] .table:not(.cbi-section-table) { + display: block; + } + + [data-page="admin-network-firewall-forwards"] .table:not(.cbi-section-table),[data-page="admin-network-firewall-rules"] .table:not(.cbi-section-table),[data-page="admin-network-hosts"] .table,[data-page="admin-network-routes"] .table { + overflow-y: visible; + } + + .commandbox { + width: 32%!important; + } + + .btn:not(button),.cbi-button { + font-size: .8rem; + } +} + +@media screen and (max-width:1152px) { + header>.fill>.container>.brand { + position: relative; + } + + html,.main { + overflow-y: visible; + } + + .main>.loading>span { + top: 25%; + } + + .main-left { + width: calc(0% + 13rem); + } + + .main-right { + width: calc(100% - 13rem); + } + + body:not(.logged-in) .showSide { + visibility: hidden; + width: 0; + margin: 0; + } + + .cbi-value-title { + width: 12rem; + padding-right: 1rem; + } + + .cbi-value-field .cbi-dropdown,.cbi-value-field .cbi-input-select,.cbi-value input[type="text"] { + width: 16rem; + min-width: 16rem; + } + + .cbi-value input[name^="pw"],.cbi-value input[data-update="change"]:nth-child(2) { + width: 13rem!important; + min-width: 13rem; + } + + #diag-rc-output>pre,#command-rc-output>pre,[data-page="admin-services-wol"] .notice code { + font-size: 1rem; + } + + .Interfaces .table { + overflow-x: hidden; + } + + #packages.table { + display: grid; + } + + .tr { + display: flex; + flex-direction: row; + flex-wrap: wrap; + } + + .Overview .table[width="100%"]>.tr { + flex-wrap: nowrap; + } + + .tr.placeholder { + border-bottom: thin solid #ddd; + } + + .tr.placeholder>.td,#cbi-firewall .tr>.td,#cbi-network .tr:nth-child(2)>.td,.cbi-section #wifi_assoclist_table .tr>.td { + border-top: 0; + } + + .th,.td { + display: inline-block; + align-self: flex-start; + flex: 2 2 10%; + text-overflow: ellipsis; + word-wrap: break-word; + } + + .td select,.td input[type="text"] { + width: 100%; + word-wrap: normal; + } + + .td [data-dynlist]>input,.td input.cbi-input-password { + width: calc(100% - 1.5rem); + } + + .td[data-type="button"],.td[data-type="fvalue"] { + flex: 1 1 12.5%; + text-align: left; + } + + .th.cbi-value-field,.td.cbi-value-field,.th.cbi-section-table-cell,.td.cbi-section-table-cell { + flex-basis: auto; + padding-top: 1rem; + } + + .cbi-section-table-row { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 rgba(0,0,0,0.12); + } + + .td.cbi-value-field,.cbi-section-table-cell { + display: inline-block; + flex: 10 10 auto; + flex-basis: 50%; + text-align: center; + } + + .td.cbi-section-actions { + vertical-align: bottom; + } + + .tr[data-title]::before,.tr.cbi-section-table-titles.named::before { + font-size: .9rem; + display: block; + flex: 1 1 100%; + border-bottom: thin solid rgba(0,0,0,0.26); + background: #e9ecef; + } + + .cbi-button+.cbi-button { + margin-left: 0; + } + + .td.cbi-section-actions>*>*,.td.cbi-section-actions>*>form>* { + margin: 2.1px 3px; + } + + .Firewall form { + position: static!important; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 rgba(0,0,0,0.12); + margin: 0 0 2rem; + padding: 2rem; + } + + .Firewall form input { + width: 100%!important; + margin: 1rem 0 0; + } + + .Firewall .center,.Firewall .center::before { + text-align: left!important; + } + + .commandbox { + width: 100%!important; + margin-left: 0!important; + } + + .btn:not(button),.cbi-button { + font-size: .8rem; + } + + header>.fill>.container>#logo,.tr.table-titles,.tr.cbi-section-table-titles,.tr.cbi-section-table-descr { + display: none; + } + + .node-main-login>.main .cbi-value-title,.td[data-title],[data-page^="admin-status-realtime"] .td[id] { + text-align: left; + } + + .table,.td[data-title]::before { + display: block; + } +} + +@media screen and (max-width:768px) { + .cbi-progressbar::after { + font-size: .5rem; + line-height: 1.5; + } + + .main-left { + position: fixed; + z-index: 100; + width: 0; + } + + .main-right { + width: 100%; + } + + .showSide { + position: relative; + z-index: 99; + display: inline-block!important; + padding: .1rem; + } + + .showSide::before { + font-family: argon!important; + font-style: normal!important; + font-weight: 400!important; + font-variant: normal!important; + text-transform: none!important; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + content: "\e20e"; + font-size: 1.7rem; + } + + header>.fill>.container>.brand { + display: inline-block; + } + + body,.main>.main-left>.nav>.slide>.slide-menu>li>a { + font-size: .8rem; + } +} + +@media screen and (max-width:600px) { + #maincontent>.container { + margin: 0 1rem 1rem; + } + + .cbi-value-title { + text-align: left; + } + + [data-page="admin-system-flash"] .cbi-value { + padding: 0 1rem; + } + + [data-page="admin-network-dhcp"] [data-tab-active="true"] { + padding: 1rem!important; + } + + .cbi-dynlist p { + padding: .5rem 1rem; + } + + body { + overflow-x: hidden; + } + + .node-main-login .main .main-right #maincontent .container .cbi-map .cbi-section .cbi-section-node .cbi-value .cbi-value-field { + width: 16rem; + } + + .tabs::-webkit-scrollbar,.cbi-tabmenu::-webkit-scrollbar { + width: 0px; + height: 0px; + } + + .cbi-value-field,.cbi-value-description { + display: block!important; + padding-left: 0!important; + padding-right: 0!important; + } + + [data-page="admin-system-admin-password"] .cbi-value-field { + display: table-cell!important; + } + + .modal.cbi-modal { + max-width: 100%; + max-height: none; + } + + .modal { + display: flex; + align-items: center; + flex-wrap: wrap; + width: 100%; + min-width: 270px; + max-width: 600px; + min-height: 32px; + border-radius: 3px!important; + background: #fff; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 rgba(0,0,0,0.12); + margin: 5em auto; + padding: 1em; + } + + .cbi-dropdown[open]>ul.dropdown { + left: .2rem!important; + right: 0!important; + margin-bottom: 1rem; + } + + .mobile-hide,.node-main-login footer { + display: none; + } + + [data-page="admin-system-flash"] legend,[data-page="admin-system-flash"] .cbi-section-descr { + padding: 1rem 0 1rem 1rem; + } +} + +@media screen and (min-width:600px) { + ::-webkit-scrollbar { + width: 10px; + height: 10px; + } + + ::-webkit-scrollbar,::-webkit-scrollbar-corner { + background: transparent; + } + + ::-webkit-scrollbar-thumb { + background: #9e9e9e; + } + + ::-webkit-scrollbar-thumb:hover { + background: #757575; + } + + ::-webkit-scrollbar-thumb:active { + background: #424242; + } +} + +@media screen and (max-width:480px) { + .mobile-hide { + display: none; + } + + .login-page .login-container { + margin-left: 0rem!important; + width: 100%; + } + + .login-page .login-container .login-form .form-login .input-group::before { + color: #525461; + } + + .login-page .login-container .login-form .form-login .input-group input { + color: #525461; + border-bottom: var(--white) 1px solid; + border-radius: 0; + } +} \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/css/dark.css b/rooter/ext-rooter-basic/files/www/luci-static/css/dark.css new file mode 100644 index 0000000..885b575 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/css/dark.css @@ -0,0 +1 @@ +body{background:#1e1e1e;color:#CCC}.login-page .login-container .login-form .form-login .input-group input{background-color:transparent!important;color:#adb5bd;border-bottom:#adb5bd 1px solid!important;border-radius:0!important;border-top:none!important;border-left:none!important;border-right:none!important;box-shadow:none}.login-page .login-container .login-form .form-login .cbi-button-apply:hover,.login-page .login-container .login-form .form-login .cbi-button-apply:focus{opacity:.9}.main .main-left{background-color:#333!important;box-shadow:0 0 .5rem 0 rgba(0,0,0,0.15)}.main .main-left .nav .slide .slide-menu li a:hover{background:none!important}.main .main-left .nav li a{color:#CCC!important}.main .main-left::-webkit-scrollbar-thumb{background-color:#252526!important}h2{color:#ccc;background:#333}h3{color:#ccc;border-bottom:0;background:#333}a:-webkit-any-link{cursor:pointer;color:var(--dark-primary)}input:-webkit-autofill{background-color:#3c3c3c!important}.cbi-value-field .cbi-input-apply,.cbi-button-apply,.cbi-button-edit{color:#fff!important;background-color:var(--dark-primary)!important;border-color:var(--dark-primary)!important}.cbi-section{background:none;box-shadow:0 0 .5rem 0 rgba(0,0,0,0.35)}.panel-title{color:#ccc;background-color:#333;border-bottom:0px}table>tbody>tr>td,table>tfoot>tr>td,table>thead>tr>td{color:#ccc;border-top:1px solid #252526}.node-system-packages>.main .cbi-section-node:first-child .cbi-value-last{line-height:1.8em}.node-system-packages>.main .cbi-section-node:first-child .cbi-value-last div[style="margin:3px 0; width:300px; height:10px; border:1px solid #000000; background-color:#80C080"]{border:1px solid #999!important;background-color:transparent!important}tr>td,tr>th,.tr>.td,.tr>.th,.cbi-section-table-row::before,#cbi-wireless>#wifi_assoclist_table>.tr:nth-child(2){border-top:0}.cbi-section>h3:first-child,.panel-title,h3{color:#ccc;border-bottom:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.cbi-progressbar{position:relative;min-width:170px;height:20px;border:thin solid #999;background:transparent;border-radius:.2rem;overflow:hidden;margin:6px 0}.cbi-button{color:#ccc!important;background-color:var(--dark-primary)}.cbi-section-node{background:none;border-radius:0 0 .375rem .375rem;padding:0rem}#content_syslog{box-shadow:0 0 .5rem 0 rgba(0,0,0,0.35)}#iwsvg,#iwsvg2,#bwsvg{overflow:hidden;box-shadow:0 0 .5rem 0 rgba(0,0,0,0.35);background-color:#1e1e1e!important}.tabs>li[class~="active"],.tabs>li:hover{border-bottom:.18751rem solid var(--dark-primary);color:#ccc;background-color:#181819}.cbi-tabmenu>li{background:#2d2d2d}.cbi-tabmenu>li:hover{color:#ccc;background:#2d2d2d}.cbi-tabmenu>li[class~="cbi-tab"]{background-color:#181819}select,input{color:#ccc;background-color:transparent!important;border:1px solid #252526;box-shadow:none}select:not([multiple="multiple"]):focus,input:focus{outline:0;border-color:var(--dark-primary)!important}.cbi-section-node .cbi-value{padding:1rem 1rem .3rem}.ifacebox{background-color:none;border:1px solid #1e1e1e}.ifacebox-head{color:#666}.zonebadge strong{color:#333}.node-services-vssr .block{background-color:#3c3c3c!important;box-shadow:0 0 .5rem 0 rgba(0,0,0,0.35)}.node-services-vssr .status-bar{color:#ccc;box-shadow:0 0 .5rem 0 rgba(0,0,0,0.35);background-color:#1e1e1e}.node-services-vssr .cbi-section-table-row{color:#ccc;background-color:#3c3c3c!important;box-shadow:0 0 5px 0 rgba(0,0,0,0.35)}.node-services-vssr .cbi-section-table-row.fast{background:var(--dark-primary)!important;color:#fff}.node-services-vssr .incon:nth-child(2){border-right:#1e1e1e 1px solid}.cbi-input-find,.cbi-input-save,.cbi-button-add,.cbi-button-save,.cbi-button-find,.cbi-input-reload,.cbi-button-reload{color:#fff!important;background:#556B2F!important;border-color:#556B2F!important}.cbi-button-reset,.cbi-input-remove{color:#fff!important;background-color:#FF8C00!important;border-color:#FF8C00!important}.cbi-page-actions .cbi-button-apply,.cbi-section-actions .cbi-button-edit,.cbi-button-edit.important,.cbi-button-apply.important,.cbi-button-reload.important,.cbi-button-action.important{border:1px var(--dark-primary) solid!important}.btn[value="Dismiss"],.cbi-button[value="Terminate"],.cbi-button[value="Reset"],.cbi-button[value="Disabled"],.cbi-button[onclick^="iface_reconnect"],.cbi-button[onclick="handleReset(event)"],.cbi-button-neutral[value="Disable"]{font-weight:400;color:#fff;border:thin solid #FF8C00!important;background-color:#FF8C00!important}#detail-bubble>div{border:1px solid #ccc;border-radius:2px;background:#252525;padding:5px}.network-status-table .ifacebox-body .ifacebadge{background-color:#252526;border-bottom:0;box-shadow:none}td>.ifacebadge,.td>.ifacebadge{background-color:var(--dark-primary);border:0}.cbi-section,.cbi-section-error,#iptables,.Firewall form,#cbi-network>.cbi-section-node,#cbi-wireless>.cbi-section-node,#cbi-wireless>#wifi_assoclist_table,[data-tab-title],[data-page^="admin-system-admin"]:not(.node-main-login) .cbi-map:not(#cbi-dropbear),[data-page="admin-system-opkg"] #maincontent>.container{background:#1e1e1e!important;box-shadow:0 0 .5rem 0 rgba(0,0,0,0.35)}div[style="width:100%;height:300px;border:1px solid #000;background:#fff"]{background:transparent!important}[data-page="admin-system-flash"] .modal label>input[type="checkbox"]{top:-0.35rem}[data-page="admin-system-flash"] .modal .btn{white-space:normal!important;background-color:#8FBC8F}[data-page="admin-system-flash"] .modal .alert-message{background-color:transparent!important}.cbi-button-positive{color:#fff!important;background-color:#556B2F!important}.logout:before{color:#adb5bd!important}.cbi-dropdown[open]{border-color:var(--dark-primary)!important}.cbi-dropdown[open]>ul.dropdown{background:#252526!important;color:#ccc!important;box-shadow:none;border:1px solid #3c3c3c!important}.cbi-dropdown[open]>ul.dropdown li{color:#ccc;border-bottom:1px solid #3c3c3c!important}.cbi-dropdown[open]>ul.dropdown>li[selected]{background-color:var(--dark-primary)!important;border-bottom:1px solid #3c3c3c!important}.cbi-dropdown[open]>ul.dropdown>li.focus{background:var(--dark-primary);outline:none}.cbi-page-actions .cbi-button-apply,.cbi-section-actions .cbi-button-edit,.cbi-button-edit,.cbi-button-apply,.cbi-button-reload,.cbi-button-action,.cbi-button[value="Submit"],.cbi-button[value="Upload"],.cbi-button[value$="Apply"],.cbi-button[onclick="addKey(event)"]{background:var(--dark-primary)!important}.btn.primary,.cbi-page-actions .cbi-button-save,.cbi-page-actions .cbi-button-apply+.cbi-button-save,.cbi-button-add,.cbi-button-save,.cbi-button-positive,.cbi-button-link,.cbi-button[value="Enable"],.cbi-button[value="Scan"],.cbi-button[value^="Back"],.cbi-button-neutral[onclick="handleConfig(event)"]{background:var(--dark-primary)}.login-page .login-container .login-form,.main .main-right,.cbi-rowstyle-2,.cbi-section-remove:nth-of-type(2n),.cbi-section-node:nth-of-type(2n),.modal{background-color:#1e1e1e}.login-page .login-container .login-form .brand,.login-page .login-container .login-form .form-login .input-group::before{color:#adb5bd}.login-page .login-container .login-form .form-login .cbi-button-apply,.notice,.cbi-value input[type="password"]+.cbi-button-neutral{background-color:var(--dark-primary)!important}header::after,header.bg-primary,select,.cbi-section-table-row{background-color:#1e1e1e!important}.main .main-left .sidenav-header .brand,.cbi-section em,.cbi-map-descr,.tabs>li[class~="active"]>a,.cbi-tabmenu>li>a,.tabs>li>a,.cbi-tabmenu>li>a:hover,.tabs>li>a:hover,.cbi-tabmenu li[class~="cbi-tab"] a,.cbi-value-title,.cbi-section-descr,.node-system-packages>.main table tr td:nth-last-child(1),.node-services-vssr .ssr-button,[data-page="admin-system-admin"] .cbi-map h2,[data-page="admin-system-admin-password"] .cbi-map h2,[data-page="admin-system-admin"] .cbi-map .cbi-map-descr,[data-page="admin-system-admin-password"] .cbi-map .cbi-map-descr,.cbi-dropdown .preview,[data-page="admin-system-flash"] legend{color:#ccc}.main .main-left .nav .slide .slide-menu .active a,.main .main-left .nav .slide .slide-menu li a{color:#CCC}.main .main-left .nav .slide .slide-menu .active a::after,.main .main-left .nav .slide .menu.active a::after{background-color:#CCC!important}.main .main-left .nav .slide .menu.active,.main .main-left .nav li a:hover{background-color:var(--dark-primary)!important;color:#CCC!important}.main .main-left::-webkit-scrollbar-track,.ifacebox-body,fieldset[id^="cbi-apply-"],.ifacebadge{background-color:#333}div>table>tbody>tr:nth-of-type(2n),div>.table>.tr:nth-of-type(2n),fieldset>table>tbody>tr:nth-of-type(2n),.cbi-rowstyle-1,div>table>tbody>tr:nth-of-type(2n),div>.table>.tbody>.tr:nth-of-type(2n),.tabs,.cbi-tabcontainer>.cbi-value:nth-of-type(2n){background-color:#252526}#swaptotal>div>div,#swapfree>div>div,#memfree>div>div,#membuff>div>div,#conns>div>div,#memtotal>div>div,.node-system-packages>.main .cbi-section-node:first-child .cbi-value-last div[style="margin:3px 0; width:300px; height:10px; border:1px solid #000000; background-color:#80C080"] div,.cbi-progressbar div,.ifacebox-head.active{background-color:#32325d!important}#swaptotal>div>div>div>small,#swapfree>div>div>div>small,#memfree>div>div>div>small,#membuff>div>div>div>small,#conns>div>div>div>small,#memtotal>div>div>div>small,#cbi-dropbear h2,#cbi-dropbear .cbi-map-descr,#cbi-dropbear .cbi-map-descr abbr,#cbi-rc h2,#cbi-rc .cbi-map-descr,#cbi-distfeedconf h2,#cbi-distfeedconf .cbi-map-descr,#cbi-customfeedconf h2,#cbi-customfeedconf .cbi-map-descr,#cbi-download h2,#cbi-filelist h2,.node-services-vssr .block h4,[data-page="admin-system-opkg"] h2{color:#ccc!important}table>tbody>tr>th,table>tfoot>tr>th,table>thead>tr>th,#cbi-wireless .td,#cbi-network .tr:first-child>.td,.table[width="100%"]>.tr:first-child>.td,[data-page="admin-network-diagnostics"] .tr>.td,.tr.table-titles>.th,.tr.cbi-section-table-titles>.th{background-color:#252526;border-bottom:#000 1px solid!important}h4,.cbi-section-table .cbi-section-table-titles .cbi-section-table-cell{background-color:#1e1e1f}abbr,div.cbi-value var,td.cbi-value-field var{color:#5e72e4}.cbi-value-field>ul>li .ifacebadge,.zonebadge>.ifacebadge{background-color:#3c3c3c}.cbi-input-textarea,#syslog,#diag-rc-output>pre{background-color:#1e1e1e;color:#ccc}#xhr_poll_status>.label.success,header .fill .status span[data-style="active"]{background-color:#556B2F!important;color:#ccc!important}.btn.danger,.cbi-section-remove>.cbi-button,.cbi-button-remove,.cbi-button-reset,.cbi-button-negative,.cbi-button[value="Stop"],.cbi-button[value="Kill"],.cbi-button[onclick="reboot(this)"],.cbi-button-neutral[value="Restart"],[data-page="admin-system-flash"] .modal .danger{background-color:#FF8C00!important;border:thin solid #FF8C00!important}.btn,button,select,input,.cbi-dropdown,.cbi-dynlist>.item>span{border:1px solid #3c3c3c!important}@media screen and (max-width:480px){.node-status-iptables>.main div>.cbi-map>form{background-color:#1e1e1e;box-shadow:0 0 .5rem 0 rgba(0,0,0,0.35)}} \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/css/fonts.css b/rooter/ext-rooter-basic/files/www/luci-static/css/fonts.css new file mode 100644 index 0000000..20dd22e --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/css/fonts.css @@ -0,0 +1 @@ +@font-face{font-family:argon;src:url(../fonts/argon.eot?u6kthm#iefix) format('embedded-opentype'),url(../fonts/argon.ttf?u6kthm) format('truetype'),url(../fonts/argon.woff?u6kthm) format('woff'),url(../fonts/argon.svg?u6kthm#argon) format('svg');font-weight:400;font-style:normal;font-display:block}[class^="icon-"],[class*=" icon-"]{font-family:argon!important;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-expand_more:before{content:"\e20b"}.icon-menu:before{content:"\e20e"}.icon-favorite:before{content:"\e291"}.icon-spinner:before{content:"\e603"}.icon-delete:before{content:"\e900"}.icon-edit:before{content:"\e901"}.icon-use:before{content:"\e902"}.icon-loading:before{content:"\e903"}.icon-switch:before{content:"\e904"}.icon-error:before{content:"\e905"}.icon-dashboard:before{content:"\e906"}.icon-logout:before{content:"\e907"}.icon-Network:before{content:"\e908"}.icon-services:before{content:"\e909"}.icon-system:before{content:"\e90a"}.icon-vpn:before{content:"\e90b"}.icon-storage:before{content:"\e90c"}.icon-statistics:before{content:"\e90d"}.icon-hello-world:before{content:"\e90e"}.icon-angle-right:before{content:"\e90f"}.icon-password:before{content:"\e910"}.icon-user:before{content:"\e971"}.icon-question:before{content:"\f059"}.icon-docker:before{content:"\e911"}.icon-control:before{content:"\e912"}.icon-statistics1:before{content:"\e913"}.icon-asterisk:before{content:"\e914"}.icon-app:before{content:"\e915"} \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/css/pure-min.css b/rooter/ext-rooter-basic/files/www/luci-static/css/pure-min.css new file mode 100644 index 0000000..43786a7 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/css/pure-min.css @@ -0,0 +1 @@ +html{line-height:1.15;-webkit-text-size-adjust:100%;font-family:sans-serif}body{margin:0}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}abbr[title]{border-bottom:none;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;white-space:normal;padding:0}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto}.pure-g{letter-spacing:-.31em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-line-pack:start;align-content:flex-start}.pure-g [class*=pure-u]{font-family:sans-serif}.pure-u-1-24{width:4.1667%}.pure-u-1-12,.pure-u-2-24{width:8.3333%}.pure-u-1-8,.pure-u-3-24{width:12.5%}.pure-u-1-6,.pure-u-4-24{width:16.6667%}.pure-u-1-5{width:20%}.pure-u-5-24{width:20.8333%}.pure-u-7-24{width:29.1667%}.pure-u-1-3,.pure-u-8-24{width:33.3333%}.pure-u-3-8,.pure-u-9-24{width:37.5%}.pure-u-2-5{width:40%}.pure-u-10-24,.pure-u-5-12{width:41.6667%}.pure-u-11-24{width:45.8333%}.pure-u-13-24{width:54.1667%}.pure-u-14-24,.pure-u-7-12{width:58.3333%}.pure-u-3-5{width:60%}.pure-u-15-24,.pure-u-5-8{width:62.5%}.pure-u-16-24,.pure-u-2-3{width:66.6667%}.pure-u-17-24{width:70.8333%}.pure-u-19-24{width:79.1667%}.pure-u-4-5{width:80%}.pure-u-20-24,.pure-u-5-6{width:83.3333%}.pure-u-21-24,.pure-u-7-8{width:87.5%}.pure-u-11-12,.pure-u-22-24{width:91.6667%}.pure-u-23-24{width:95.8333%}.pure-button{display:inline-block;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:inherit;font-size:100%;color:rgba(0,0,0,.8);border:none transparent;background-color:#e6e6e6;text-decoration:none;border-radius:2px;padding:.5em 1em}.pure-button::-moz-focus-inner{border:0;padding:0}.pure-button-group{letter-spacing:-.31em;text-rendering:optimizespeed}.pure-button-group .pure-button{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto;border-radius:0;border-right:1px solid rgba(0,0,0,.2);margin:0}.pure-button-hover,.pure-button:focus,.pure-button:hover{background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000}.pure-button-disabled,.pure-button-disabled:active,.pure-button-disabled:focus,.pure-button-disabled:hover,.pure-button[disabled]{border:none;background-image:none;opacity:.4;cursor:not-allowed;-webkit-box-shadow:none;box-shadow:none;pointer-events:none}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-button-group .pure-button:first-child{border-top-left-radius:2px;border-bottom-left-radius:2px}.pure-button-group .pure-button:last-child{border-top-right-radius:2px;border-bottom-right-radius:2px;border-right:none}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{display:inline-block;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 3px #ddd;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;box-sizing:border-box;padding:.5em .6em}.pure-form input:not([type]){display:inline-block;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 3px #ddd;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;box-sizing:border-box;padding:.5em .6em}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=checkbox]:focus,.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus{outline:1px auto #129fea}.pure-form .pure-checkbox,.pure-form .pure-radio{display:block;margin:.5em 0}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form select:focus:invalid,.pure-form textarea:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=checkbox]:focus:invalid:focus,.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{border:0;margin:0;padding:.35em 0 .75em}.pure-form legend{display:block;width:100%;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5;padding:.3em 0}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form .pure-input-rounded,.pure-form input.pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;border-radius:0;position:relative;top:-1px;margin:0 0 -1px;padding:10px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-3{width:33%}.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}.pure-menu{-webkit-box-sizing:border-box;box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-item,.pure-menu-list{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{height:100%;margin:0;padding:0}.pure-menu-heading,.pure-menu-link{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-children{display:none;position:absolute;left:100%;top:0;z-index:3;background-color:#fff;margin:0;padding:0}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-active>.pure-menu-children,.pure-menu-allow-hover:hover>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;padding:.5em 0}.pure-menu-horizontal .pure-menu-children .pure-menu-separator,.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-horizontal .pure-menu-children .pure-menu-separator{display:block;width:auto}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-disabled,.pure-menu-heading,.pure-menu-link{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-active>.pure-menu-link,.pure-menu-link:focus,.pure-menu-link:hover{background-color:#eee}.pure-menu-selected>.pure-menu-link,.pure-menu-selected>.pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;text-align:center;padding:1em 0}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;font-size:inherit;overflow:visible;border-width:0 0 0 1px;margin:0;padding:.5em 1em}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-horizontal td,.pure-table-horizontal th{border-bottom:1px solid #cbcbcb;border-width:0 0 1px}main,details,.pure-menu-item .pure-menu-item,.pure-menu-scrollable .pure-menu-list{display:block}pre,code,kbd,samp{font-family:monospace,monospace;font-size:1em}a,.pure-menu-disabled .pure-menu-link:hover,.pure-table td{background-color:transparent}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button,.pure-form select[multiple]{height:auto}template,[hidden],.pure-button-hidden{display:none}.opera-only :-o-prefocus,.pure-g,.opera-only :-o-prefocus,.pure-button-group{word-spacing:-.43em}.pure-u,.pure-u-1,.pure-u-1-1,.pure-u-1-12,.pure-u-1-2,.pure-u-1-24,.pure-u-1-3,.pure-u-1-4,.pure-u-1-5,.pure-u-1-6,.pure-u-1-8,.pure-u-10-24,.pure-u-11-12,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-2-24,.pure-u-2-3,.pure-u-2-5,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24,.pure-u-3-24,.pure-u-3-4,.pure-u-3-5,.pure-u-3-8,.pure-u-4-24,.pure-u-4-5,.pure-u-5-12,.pure-u-5-24,.pure-u-5-5,.pure-u-5-6,.pure-u-5-8,.pure-u-6-24,.pure-u-7-12,.pure-u-7-24,.pure-u-7-8,.pure-u-8-24,.pure-u-9-24{display:inline-block;letter-spacing:normal;text-rendering:auto;vertical-align:top;word-spacing:normal}.pure-u-1-4,.pure-u-6-24,.pure-form .pure-input-1-4{width:25%}.pure-u-1-2,.pure-u-12-24,.pure-form .pure-input-1-2{width:50%}.pure-u-18-24,.pure-u-3-4,.pure-form .pure-input-3-4{width:75%}.pure-u-1,.pure-u-1-1,.pure-u-24-24,.pure-u-5-5,.pure-form .pure-input-1{width:100%}.pure-form input[type=color]:focus,.pure-form input[type=date]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=email]:focus,.pure-form input[type=month]:focus,.pure-form input[type=number]:focus,.pure-form input[type=password]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=text]:focus,.pure-form input[type=time]:focus,.pure-form input[type=url]:focus,.pure-form input[type=week]:focus,.pure-form select:focus,.pure-form textarea:focus,.pure-form input:not([type]):focus{outline:0;border-color:#129fea}.pure-form input[type=color][disabled],.pure-form input[type=date][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=email][disabled],.pure-form input[type=month][disabled],.pure-form input[type=number][disabled],.pure-form input[type=password][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=text][disabled],.pure-form input[type=time][disabled],.pure-form input[type=url][disabled],.pure-form input[type=week][disabled],.pure-form select[disabled],.pure-form textarea[disabled],.pure-form input:not([type])[disabled]{background-color:#eaeded;color:#cad2d3;cursor:not-allowed}.pure-form-stacked input[type=color],.pure-form-stacked input[type=date],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=email],.pure-form-stacked input[type=file],.pure-form-stacked input[type=month],.pure-form-stacked input[type=number],.pure-form-stacked input[type=password],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=text],.pure-form-stacked input[type=time],.pure-form-stacked input[type=url],.pure-form-stacked input[type=week],.pure-form-stacked label,.pure-form-stacked select,.pure-form-stacked textarea,.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned select,.pure-form-aligned textarea,.pure-form-message-inline,.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-separator{display:inline-block;vertical-align:middle}.pure-menu-horizontal .pure-menu-list,.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-table-odd td,.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered tbody>tr:last-child>td,.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){table .pure-g{display:block}}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=color],.pure-group input[type=date],.pure-group input[type=datetime-local],.pure-group input[type=datetime],.pure-group input[type=email],.pure-group input[type=month],.pure-group input[type=number],.pure-group input[type=password],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=text],.pure-group input[type=time],.pure-group input[type=url],.pure-group input[type=week]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form-message,.pure-form-message-inline{display:block;font-size:.75em;padding:.2em 0 .8em}} \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/Roboto-Medium-webfont.woff b/rooter/ext-rooter-basic/files/www/luci-static/fonts/Roboto-Medium-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..9024faeb8f52376392077cb7f343b072e318daa4 GIT binary patch literal 70200 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 literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/Roboto-Regular-webfont.woff b/rooter/ext-rooter-basic/files/www/luci-static/fonts/Roboto-Regular-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..5413a37ee0c57147ef81660849eebd5c3531cdaf GIT binary patch literal 68776 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 literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.eot b/rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.eot new file mode 100644 index 0000000000000000000000000000000000000000..efce636a84d6da92d5e40498fc945e93a90e4307 GIT binary patch literal 33846 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 M>%j(UEQQ4X1Pp)(oB#j- literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.svg b/rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.svg new file mode 100644 index 0000000..c555b75 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.svg @@ -0,0 +1,1191 @@ + + + + +Created by FontForge 20090622 at Tue Jul 23 03:29:07 2019 + By deploy user +TypoGraphica ©Sharkshock Productions 2015. All Rights Reserved + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.ttf b/rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e11f89a0f749b95a9001e33de3100be7a0bb858e GIT binary patch literal 33632 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 literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.woff b/rooter/ext-rooter-basic/files/www/luci-static/fonts/TypoGraphica.woff new file mode 100644 index 0000000000000000000000000000000000000000..fef38ca003e3d02372d80287057424843e6bd4f0 GIT binary patch literal 17816 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 P{|_V(EFb^?vO@>^k62-U literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.eot b/rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.eot new file mode 100644 index 0000000000000000000000000000000000000000..f85324aacd32146dc3f40b9fae97c20273f43bd0 GIT binary patch literal 8480 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 literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.svg b/rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.svg new file mode 100644 index 0000000..a4ae739 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.svg @@ -0,0 +1,53 @@ + + + +Generated by Fontastic.me + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.ttf b/rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0f59478d517233be2269d3e7f719649444b101d6 GIT binary patch literal 8288 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

                                                                        ?Nv5>2jM{^Uow~~U2 z`fzo)GCGE)?>72xE#XEGcMrRl-4&3W!(@U?cH_c5_ujRCF*jC5;eRzC?D*wZYkx1V zX`Q3NzyjAOI4$R-kxm8<3oNoJf>U^hViYHr5|ktl|6!#lO>LB+cIu!`%2F5QC{Nu~ zpdRX_B9*8Qr%?kmNJH9vi+8OV9UTqRu`sQKX*Ep8!?YHr^)S66Os@>nRbje1Os@&k zHLY|koM$YYXDpm&ESzU79Dghvf2A}-by%cC7ic%Xk(1{{V>3wP64N literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.woff b/rooter/ext-rooter-basic/files/www/luci-static/fonts/advancedtomato.woff new file mode 100644 index 0000000000000000000000000000000000000000..42512481990775135c4da591e761b1b51c408234 GIT binary patch literal 6272 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 H0qFk=!5PYt literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.eot b/rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.eot new file mode 100644 index 0000000000000000000000000000000000000000..e28f6db55e898dd8a1d9ead5318f7528ec9286c4 GIT binary patch literal 8888 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 JAO6eX{{!P-6bb+U literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.svg b/rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.svg new file mode 100644 index 0000000..1e12b5f --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.svg @@ -0,0 +1,38 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.ttf b/rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3d062dcf264462eae98dbe9565560187362e7f5c GIT binary patch literal 8732 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 DNS*~X literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.woff b/rooter/ext-rooter-basic/files/www/luci-static/fonts/argon.woff new file mode 100644 index 0000000000000000000000000000000000000000..ef1e9c2c434f786a409d2e3ac47a5035872e98e7 GIT binary patch literal 8808 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 b$ejqMF;>UORRG?q5=PhE&nt)jo%sI(Ce#aG literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/font.eot b/rooter/ext-rooter-basic/files/www/luci-static/fonts/font.eot new file mode 100644 index 0000000000000000000000000000000000000000..9e6ffc9b826cb39a58e56359d6b8b922a4b07364 GIT binary patch literal 1912 zcmah~Ur1Y582`?_x%Vc~T>r!*OpT4P8o`m;m_K$==`c84Z6{8{+A(HKZlhvuY>cgr zKFA)%(1*FfM*FnUZZIZ{J&ZBvpfZF#Y)@lIVSRG2hwi1Y4#u`F`<;8QXe6-ja?bgE zzwN>ij! zo>pmzGE@TNr8Jlltw75)0Xj=z>Nm6}M}y=6>u7^S>VN6wGm(a7S2vh%P-e4*%<|74 z-T45bcKGFdW@Q;|Bm8Z&_WaWN)fd`ZeusaHNO&->WpYaP$#+CHu8YruP`(wvhyN-3 z)ANP$nqL?8;r{@?cd3}o2=nYs_)p+_3z@ZLe9%0RR1ZI(XA0Ww7af1Ye-<&`S}v}X zF;AHMCGRIuyn~rYh<#h&Z+ypW*>5z!99(zI7^Yoq=ZPL)7I!PVbY4V3=V9`>F2E}z z8jskHKC=}KRXf?}74Xf-hKS{56ga3mP!HbyReXH8^0ZRngTXngI9B<^|Cj$y|Mga> z;R}pA9?uwniV?%;hGTu$Jc)CL^hp0d9A5GarZvNJ<6ufi3Gpco?d=T-GZmvH1`UH| zm}{8N!4f`UZ>U1NTNno5ddx?}-q;a0gdKdb1FJ*sPETj7DTdm^s|}H!LSzj^@e}6Xo3K zXf!%Jyy+jD4Tn>yMB=%*RO-r=RBGa)o-oe4%#d}+m|4=Q~$QQ44QKuG~z>i4Xv1q8Lj|COk&su!m zB#R{CF*mpnCZx!x7-pM@8!0(V$8jZ+b@ar1M!vd&d^FFaIShFeNRsTjU4j|Sd#3{Z zXChnUcGm@);*d_c-5qUSPhEZ6>5dLdQtxVZJDg384u_&VOeQt$##&BG!nEAl4Grj% zf?bkj$zHI_k|f*NMx?LL=UZ2u=WI$ybv3ANugm3X>D=4hK9vL(>`jZV6X?ab{kvf)^jN}pSC8R2xdumC)3 zVG%fPVH@zOg(aM_9t+FhFId=#{kw^X%;o^2qQ}GnaNfcq@UVq#z&9-{;jj-_SO!03 zVJAiDPgt_+pY=D^L-I_h!b%DZS?d0}MTT%Y6XQicBm D*A6pu literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/font.svg b/rooter/ext-rooter-basic/files/www/luci-static/fonts/font.svg new file mode 100644 index 0000000..d38d057 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/fonts/font.svg @@ -0,0 +1,16 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/font.ttf b/rooter/ext-rooter-basic/files/www/luci-static/fonts/font.ttf new file mode 100644 index 0000000000000000000000000000000000000000..84669323e9ddfdca80c91416b6d4fe31ea1829ab GIT binary patch literal 1748 zcmah}U1%d!6h3n&Gn1cY`jbCwn>0i)RYHn=Nd(_}VjX(rt? z-ECzbiVq^~gR7wIJ}Ik$SP&mXgcU4O@Ijw^C=2dW1t0Wf!4*VZ<9BDKw5tWraPR%j zch0@%%sF?41R`?L28k4Z?)j66)(&?+m@hHriq*pM5AWT1he+s#-Y6GVma(=$zlqge zURuBMOt<$}=(mX2y^2;SDaD815ZSn2x&lJ^TKpFJN6=4Hs*Sav&i0^x2YqmLYKX+Z zh4)?i>i(NQi4QI{A2plC?(n|zF-~ay82lsnd+=JP)cPs*9gSyfz$B1>-K|G#j3{&3 za6R<@9}b5+fwX3MZ5)CURiZq_(cRrqHrq5-65u1iXN>y@0f&$Yu-(xnaWfkO;Qq)* z#NF5yH`q4b*n#elr`Ok;YENPI@o7V(M{qI++s^0z-kX`(%jfy~2$ZLw_^~)dT}1uS z0rN>EGwI<(fDgaVtH^j5jW5RI*{t6`F;QxqJJ%>pOeB+IW1GQ|xmYZh%VeIK&*d&( z&gJGW%*>3B-$2WWnmaZ^=Q=5cP!W|W1*=Ev4Ne;?! z)Dy)zd{P0UUVRb1o7d6YhB`8mB)e{xAja}mPdI)uu{C9PpS39tsmJ39b@_d+maY?_ zkmb_i?(jIA?QIT+qTJ7BHSPLZNy|dC(%N+m=)h}3M^?w~_ggCg@Q$N?gdbxG{B zx-Tq&<|jJo3a&GkgUE(rO)7n2#T7^aXXe0w=PWD&r!8y)UbV1p!rv)lfjj9+m((_t< zWuc~rPsQT+HZ`i#3LId-Ij1N_@nd%#OHOO$)ulomK{X`0N=sCr`mvsqHN6ooYr0l1 zG_+E9emy)@ter=0F`6`DHxRvyV{{{<0yVIfz|GS-<|*R^&YLfQ9MQz1E%`702g#=) A_5c6? literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/fonts/font.woff b/rooter/ext-rooter-basic/files/www/luci-static/fonts/font.woff new file mode 100644 index 0000000000000000000000000000000000000000..00cf84ea037c9748eba8fced0acff7dd29c12b2f GIT binary patch literal 1824 zcmah~U1%d!6h3z*Gn1dq^e2DXHffq}n?fO*P4m+=ZK*U=>UMvqZE#n_rpav5(j>cS zx@~12iVq^~gR7vpPs*;oSP-8?SivF%AM{D2EZCG7&Rrx~vs#LD8 z6G>0NAK>b*2>Z*`Jo2P*_+G9;iM>+Jt)s5=Jp7=pDwQg^vIY+G*{fXdJZt;odUXZ8 zDo8Q&L?BVT%Wji|-tGur!++fv+0Qh@Y&`XZu+|ff4#$ZeUJ-X2yEHCB!7-gTOi&;6 zDnMO`aoh#Vv%1Jayytdm1tWk99y$)y!#92uA6{uZZZr@haQ1(2tnt17cmHqxn;lZi z$L30U;t9iuVRnmN#h?YE)H%Ji~}l4#fh3$L$@8 zB@^+8(AyRp6H=J9PPd>@Tz*hhgR$y%{W5Pf*FI~Y9^ z+n%yI&s!9m)a`NwI=vppsm{}ZfSGd2+3vF0+gfclML9^PHEnIZprs*NVSP;l`k-u; zWLdJ7t+FJ^R<;=%9Q64%RQoxL5>}lps>|ziI$L`}{T`#RqrJ^xmt|E|ogPm| zCrxYtUNy0VFSW^2&zRUw zae99-UoBUw6 + */ + +@font-face { + font-family: 'Roboto'; + src: local('Roboto Medium'), local('Roboto-Medium'), url('Roboto-Medium-webfont.woff') format('woff'); + font-weight: 500; + font-style: normal; +} + +@font-face { + font-family: 'Roboto'; + src: local('Roboto'), local('Roboto Regular'), local('Roboto-Regular'), url('Roboto-Regular-webfont.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'icomoon'; + src: url('font.eot'); + src: url('font.eot') format('embedded-opentype'), + url('font.ttf') format('truetype'), + url('font.woff') format('woff'), + url('font.svg') format('svg'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: "advancedtomato"; + src:url("advancedtomato.eot"); + src:url("advancedtomato.eot?#iefix") format("embedded-opentype"), + url("advancedtomato.woff") format("woff"), + url("advancedtomato.ttf") format("truetype"), + url("advancedtomato.svg#advancedtomato") format("svg"); + font-weight: normal; + font-style: normal; +} diff --git a/rooter/ext-rooter-basic/files/www/luci-static/icon/android-icon-192x192.png b/rooter/ext-rooter-basic/files/www/luci-static/icon/android-icon-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..7c17009d3d83e8d0aedf334165c8fcdf95df501b GIT binary patch literal 6411 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 literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/icon/apple-icon-144x144.png b/rooter/ext-rooter-basic/files/www/luci-static/icon/apple-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..5308d66b779b26d1828690516a4ab5dc01b7cec9 GIT binary patch literal 5222 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 aWS&p(fIu!(CjkFLSj>$d8r2y%$NwKzaNBSI literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/icon/apple-icon-60x60.png b/rooter/ext-rooter-basic/files/www/luci-static/icon/apple-icon-60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..f18dfa49cd35fa6d5cb882ea8ae703c852e313df GIT binary patch literal 2561 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 literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/icon/apple-icon-72x72.png b/rooter/ext-rooter-basic/files/www/luci-static/icon/apple-icon-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..bb3e2423331068c72c5ad0e1bc49a51e1fdd71af GIT binary patch literal 2877 zcmYjSc{tSD8=r0}vX+WuN!ij(L|36)A(HGRB#dS3W{feIF_y*{)QDuu_ERKVCP@?$ zB}*himadx^%Ph>8efxcTe*gT=bIyCt`8?12p3nO^?|Dv^i<6z~UX{Hd5J>ily^R|% z+y5StI{^zewnhMx1jOo^6$nJkl@bi=&4v0EVJB1CblC z89e_uQdAlfl0*$oB*$e6pm#V3ya*h><_BMnNoU1pi^DPWkR(b(3Ox|H9-h4Q+hXWI zhh=bqemnM8Sn?)-0}Euf_;&0v;P}6Fe3l46klDX&L<%D^l>r2aOkn_92#O{aivh=| z)a`K0Rw$YV;6P;P9X2?A6@sG1W^jR+(P_*G3?1--VmSc_QXp~-pyVI70>g3uN&sOP zmIucP5O^WLJUX2fo52r5Zw4i-$J}8DC2T;FC}C(Ca5O+EJb4q~6Ou>{PS^-V(Lzzw z$W$gkDKLHwNES#WDvcF{Tn8goMIvzkVik_#0h$2%1jLcTF${rF3emkLMBVhV2YMVLV-Z+2VVilugBp9TMRLqBOadySaBw2g(1J?rIKmCr3g>n z{{BN4il+1UVxdrcx0DWumQl!wPG@%y@E4bbs~f_I6eev;H1bt|y2piKw`0;73qJ)> zY3#;!AYV@Zh+uGB2x$1clMP00)V^Scq5-Y8!jkFj?>H}egs6LhgsknAHPP5NVPp#P zO+T-whSl(jgSpQyuNS1{^QxPfkty_bvWUYK|J?v-&rjq%|b4B{I> zX`QgJhTqg7#6AQ9ZX&Zb8{3)T=#Bg;I<9cDs*w?#u--c;>K)=`77KDK1sDQ=P@bU) zQ@|VeGtSM)9rXVHTi;Ie_qtP|9Q9D$soJzOb55=LbZr_(eY!8Lc8WiDdRYnt+Vl8| zjg`mEzNVSPn~D$>(59=8&nbtkS8P_x0ON#&2j1JK&3m8z2JvU}Ou_6EZ>(11n-Im8 zyrWVlur2s`Nj>&)S-hm=AF)ZUP2{9hyWXAsHz-|E$nP;{j7yMmll8R9!C!30?zf(} zqo1Ja#?(aJGwQH@#WQQ=^Vs4t$}IvBprNC!?Q36uZTZ&?n+#PmEs63r%a?r(ODKd{?T@Z5)Y8AG z(sQdLYPJ?T___REWoXoPui=cTfqFLX#Af0isGj6DQE|~F$`S|TJI|iD|Llc8j#qXC zLY0(B>+akyVs%{QCO6JW7{ANus_eL^{D;%fb*Rj%%J&?hVUv^lO0vpX8CFZp-NqouQt3Kng0xwwO%WQ7@@ z-AVs~*1{Z@&ebeK^?b#;&=9aB)v_~g=4dcQe08T&&Tf`Za@)Rh%1L)y?bfmb>>hp~ zc^%fJdY^>EnL<_f|0D-?(!4ub4W}Kvltxmr4EAp`6*aarXg6V=

                                                                        l43o znrK}nG+gtc>gLx>3i3^0x2Jw8raK+QC7@P3yP)0$WkXdfo&(SJ7avZx7?9gye*=Fh z7^#U3mveCVTs5L%k>I3&;}DR@Gbl&OjgX3u6tH~ViyWGN=xhHJmXqb75p?YjBWI!7 zXQOk-o;;ew1%hU;dPQNyb1>nPku#Dsp8165-LI*cm;3`hb@pts4Q9lGd3wP*%H&|w z#Y>P2Qdtzn;Zr^Nrr-KTgP$9mN;J=My)3^EvJclURe zzxaz!|C)L*;B4u@+V+tfo@4yjLty;pzP;DbiSEZ!{C2@hNG7H+L8>yc0aV=!#xqsf_rp|b*a?=O zdkVxzBZ`Xxvy1NF!Of&k>bbv|?No7}*&6tlNnM-BoI~GLkBVxAjG^a7Bjs-?yuPT{ zaCZ9d049+>}fFM zCuM`!K6?G2=tfO`8%FKLCo0w-FIs3?#=UL&dYAFn92b2cl7NrqHomX5^lw6=lPxZ;uW0c%Ty}83g+jQYV9D~#HHw~lDUs=oH8a=Hj`uh= z!BzHhEOD6gYOc$2dw7sCJ#_5-L+xxIh_vkW9Hl+35F2w2p`x1c-S~PyU#40vro1qf z*QDd|-L1B<&Pe-a=&Hu+2vT?+eYlk`b3I7pU$^P^vQ=OUo=@of5wksfpx*xpfoHPg z!}gpIjQ$ldh4xh7F>6ZzF;idtxrrv>4EFQ(l?hCGu#Ysm{Jp zXJe*zQIKhfkM@M2hi6x1BfELj=@yOO&>qu%Go-mBjM(Vo_eJ%p|Htkl^Wku3@3Zi>ZKo#XAY5CTVcnVy;=;QYF>U;ju%hgvOoXWk7$Wk8E$eH zKVY6^yFDE_AM>65v32|SDW&Lg9*xEG9bJW#WJW69eso4uvF_WS$dy0c_5LCYUSYC@ zDDu<@1|K+ld`9`>$0d)uPr%!slyse{)ip#KSRIf?hg$kD@Xdp+*gDxXU-D1?FEo)L Ao&W#< literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/icon/browserconfig.xml b/rooter/ext-rooter-basic/files/www/luci-static/icon/browserconfig.xml new file mode 100644 index 0000000..c554148 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/icon/browserconfig.xml @@ -0,0 +1,2 @@ + +#ffffff \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/icon/favicon-16x16.png b/rooter/ext-rooter-basic/files/www/luci-static/icon/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..308843a09261dc8c5d95f01a3b4e6592e1a83ff0 GIT binary patch literal 1019 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 aWS&p(fIu!(CjkFLSj>$d8r2y%$NwKzaNBSI literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/icons/arrow.svg b/rooter/ext-rooter-basic/files/www/luci-static/icons/arrow.svg new file mode 100644 index 0000000..be864c5 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/icons/arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/icons/logout.svg b/rooter/ext-rooter-basic/files/www/luci-static/icons/logout.svg new file mode 100644 index 0000000..d529b94 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/icons/logout.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/icons/menu.svg b/rooter/ext-rooter-basic/files/www/luci-static/icons/menu.svg new file mode 100644 index 0000000..46bd0ae --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/icons/menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/icons/spinner.svg b/rooter/ext-rooter-basic/files/www/luci-static/icons/spinner.svg new file mode 100644 index 0000000..6ddd3b3 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/icons/spinner.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/img/argon.svg b/rooter/ext-rooter-basic/files/www/luci-static/img/argon.svg new file mode 100644 index 0000000..654e2fe --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/img/argon.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rooter/ext-rooter-basic/files/www/luci-static/img/blank.png b/rooter/ext-rooter-basic/files/www/luci-static/img/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..9f4100e6e2ea2fa08912439eb7425af3f048eedd GIT binary patch literal 938 zcmaJ=L66cv6t0pOLtGQRxu;1t8cn3rmX@UxDuEV+#1g`iEC&ykc7V#ZQ`^B74o1E0 z!9@RtCjJ4Vo;`W;;-Byjn5vqfmTeG-$ z^$PpHk-vXt%Pra((IYaUi5+3C;gT^1UEiMK0k+-cvv0V@afLhHa70JeBjgZYurrL1 z`XOU;T&;m#;qnwG=S{ zA5$Bo{z(v{ROi>ah{f44|Y zg;KdBRgfYgSq7VrXW1fmf(B-LlZ)+ienx4CAWV`(NXi0_9I4~G;sIW3tW=K z_tqTCLfs&ycHrQysq;)l@H`ilE0WPRn-#+l6-jC}G^uPDimIwwvsqP|M$R>fv+!|1 zbFO>AJ>1F7#=#F+W)nx=bL_Sw;)8YB$lL8j*{QeTy1TuoJGqdVf!XE$b=mn5o1iS* zjxO75haU%Q;v+WNFFxG9&Ys17*K7>apX1+WXZ3>g^7K_leE${|FI~RI{kU1U@$}2P Q$Jy)YwtD8r=9AZd04Jv&d;kCd literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/img/open.png b/rooter/ext-rooter-basic/files/www/luci-static/img/open.png new file mode 100644 index 0000000000000000000000000000000000000000..7c92fbee992c314b7d1974b6a5dec664e2985feb GIT binary patch literal 7603 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 V)c(S)E{XsE002ovPDHLkV1h0R-5US^ literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/img/volume_high.svg b/rooter/ext-rooter-basic/files/www/luci-static/img/volume_high.svg new file mode 100644 index 0000000..f01ad5c --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/img/volume_high.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/img/volume_off.svg b/rooter/ext-rooter-basic/files/www/luci-static/img/volume_off.svg new file mode 100644 index 0000000..0598d58 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/img/volume_off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/rooter/ext-rooter-basic/files/www/luci-static/resources/buttons/buttons.css b/rooter/ext-rooter-basic/files/www/luci-static/resources/buttons/buttons.css new file mode 100644 index 0000000..9f4b624 --- /dev/null +++ b/rooter/ext-rooter-basic/files/www/luci-static/resources/buttons/buttons.css @@ -0,0 +1,702 @@ +/* Buttons CSS */ + +:root { + --green-color: rgb(44,187,99); + --red-color: rgb(218,42,42); +} + +/* +

                                                                        <%:Exit%>
                                                                        +*/ + +.button-73 { + appearance: none; + background-color: #FFFFFF; + border-radius: 40em; + border-style: none; + box-shadow: #ADCFFF 0 -12px 6px inset; + box-sizing: border-box; + color: #000000; + cursor: pointer; + display: inline-block; + font-family: -apple-system,sans-serif; + font-size: 1.2rem; + font-weight: 700; + letter-spacing: -.24px; + margin: 0; + outline: none; + padding: 1rem 1.3rem; + quotes: auto; + text-align: center; + text-decoration: none; + transition: all .15s; + user-select: none; + -webkit-user-select: none; + touch-action: manipulation; +} + +.button-73:hover { + background-color: #FFC229; + box-shadow: #FF6314 0 -6px 8px inset; + transform: scale(1.125); +} + +.button-73:active { + transform: scale(1.025); +} + +@media (min-width: 768px) { + .button-73 { + font-size: 1.5rem; + padding: .75rem 2rem; + } +} + +/* +
                                                                        <%:Exit%>
                                                                        +*/ +.button-71 { + background-color: #0078d0; + border: 0; + border-radius: 56px; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: system-ui,-apple-system,system-ui,"Segoe UI",Roboto,Ubuntu,"Helvetica Neue",sans-serif; + font-size: 1.25rem; + font-weight: 600; + outline: 0; + padding: 16px 21px; + position: relative; + text-align: center; + text-decoration: none; + transition: all .3s; + user-select: none; + -webkit-user-select: none; + touch-action: manipulation; +} + +.button-71:before { + background-color: initial; + background-image: linear-gradient(#fff 0, rgba(255, 255, 255, 0) 100%); + border-radius: 125px; + content: ""; + height: 50%; + left: 4%; + opacity: .5; + position: absolute; + top: 0; + transition: all .3s; + width: 92%; +} + +.button-71:hover { + box-shadow: rgba(255, 255, 255, .2) 0 3px 15px inset, rgba(0, 0, 0, .1) 0 3px 5px, rgba(0, 0, 0, .1) 0 10px 13px; + transform: scale(1.05); +} + +@media (min-width: 768px) { + .button-71 { + padding: 16px 48px; + } +} + +/* +
                                                                        <%:Exit%>
                                                                        +*/ +.button-62 { + background: linear-gradient(to bottom right, #EF4765, #FF9A5A); + border: 0; + border-radius: 12px; + color: #FFFFFF; + cursor: pointer; + display: inline-block; + font-family: -apple-system,system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; + font-size: 16px; + font-weight: 500; + line-height: 2.5; + outline: transparent; + padding: 0 1rem; + text-align: center; + text-decoration: none; + transition: box-shadow .2s ease-in-out; + user-select: none; + -webkit-user-select: none; + touch-action: manipulation; + white-space: nowrap; +} + +.button-62:not([disabled]):focus { + box-shadow: 0 0 .25rem rgba(0, 0, 0, 0.5), -.125rem -.125rem 1rem rgba(239, 71, 101, 0.5), .125rem .125rem 1rem rgba(255, 154, 90, 0.5); +} + +.button-62:not([disabled]):hover { + box-shadow: 0 0 .25rem rgba(0, 0, 0, 0.5), -.125rem -.125rem 1rem rgba(239, 71, 101, 0.5), .125rem .125rem 1rem rgba(255, 154, 90, 0.5); +} + +/* +
                                                                        + + + + Button 82 + +
                                                                        + + Red button +*/ + +.button-82-pushable { + position: relative; + border: none; + background: transparent; + padding: 0; + cursor: pointer; + outline-offset: 4px; + transition: filter 250ms; + user-select: none; + -webkit-user-select: none; + touch-action: manipulation; +} + +.button-82-shadow { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: 12px; + background: hsl(0deg 0% 0% / 0.25); + will-change: transform; + transform: translateY(2px); + transition: + transform + 600ms + cubic-bezier(.3, .7, .4, 1); +} + +.button-82-edge { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: 12px; + background: linear-gradient( + to left, + hsl(340deg 100% 16%) 0%, + hsl(340deg 100% 32%) 8%, + hsl(340deg 100% 32%) 92%, + hsl(340deg 100% 16%) 100% + ); +} + +.button-82-front { + display: block; + position: relative; + padding: 12px 27px; + border-radius: 12px; + font-size: 1.1rem; + color: white; + background: hsl(345deg 100% 47%); + will-change: transform; + transform: translateY(-4px); + transition: + transform + 600ms + cubic-bezier(.3, .7, .4, 1); +} + +@media (min-width: 768px) { + .button-82-front { + font-size: 1.25rem; + padding: 12px 42px; + } +} + +.button-82-pushable:hover { + filter: brightness(110%); + -webkit-filter: brightness(110%); +} + +.button-82-pushable:hover .button-82-front { + transform: translateY(-6px); + transition: + transform + 250ms + cubic-bezier(.3, .7, .4, 1.5); +} + +.button-82-pushable:active .button-82-front { + transform: translateY(-2px); + transition: transform 34ms; +} + +.button-82-pushable:hover .button-82-shadow { + transform: translateY(4px); + transition: + transform + 250ms + cubic-bezier(.3, .7, .4, 1.5); +} + +.button-82-pushable:active .button-82-shadow { + transform: translateY(1px); + transition: transform 34ms; +} + +.button-82-pushable:focus:not(:focus-visible) { + outline: none; +} + +/* +
                                                                        <%:Exit%>
                                                                        + Green button +*/ + +.button-33 { + background-color: #c2fbd7; + border-radius: 100px; + box-shadow: rgba(44,187,99, .2) 0 -25px 18px -14px inset,rgba(44,187,99, .15) 0 1px 2px,rgba(44,187,99, .15) 0 2px 4px,rgba(44,187,99, .15) 0 4px 8px,rgba(44,187,99, .15) 0 8px 16px,rgba(44,187,99, .15) 0 16px 32px; + color: green; + cursor: pointer; + display: inline-block; + font-family: CerebriSans-Regular,-apple-system,system-ui,Roboto,sans-serif; + padding: 7px 20px; + text-align: center; + text-decoration: none; + transition: all 250ms; + border: 0; + font-size: 20px; + user-select: none; + -webkit-user-select: none; + touch-action: manipulation; +} + +.button-33:hover { + box-shadow: rgba(44,187,99,.35) 0 -25px 18px -14px inset,rgba(44,187,99,.25) 0 1px 2px,rgba(44,187,99,.25) 0 2px 4px,rgba(44,187,99,.25) 0 4px 8px,rgba(44,187,99,.25) 0 8px 16px,rgba(44,187,99,.25) 0 16px 32px; + transform: scale(1.05) rotate(-1deg); +} + +/* Red button */ + +.button-34 { + background-color: var(--red-color); + border-radius: 100px; + box-shadow: rgba(218,42,42, .2) 0 -25px 18px -14px inset,rgba(218,42,42, .15) 0 1px 2px,rgba(218,42,42, .15) 0 2px 4px,rgba(218,42,42, .15) 0 4px 8px,rgba(218,42,42, .15) 0 8px 16px,rgba(218,42,42, .15) 0 16px 32px; + color: green; + cursor: pointer; + display: inline-block; + font-family: CerebriSans-Regular,-apple-system,system-ui,Roboto,sans-serif; + padding: 7px 20px; + text-align: center; + text-decoration: none; + transition: all 250ms; + border: 0; + font-size: 20px; + user-select: none; + -webkit-user-select: none; + touch-action: manipulation; +} + +.button-34:hover { + box-shadow: rgba(218,42,42,.35) 0 -25px 18px -14px inset,rgba(218,42,42,.25) 0 1px 2px,rgba(218,42,42,.25) 0 2px 4px,rgba(218,42,42,.25) 0 4px 8px,rgba(218,42,42,.25) 0 8px 16px,rgba(218,42,42,.25) 0 16px 32px; + transform: scale(1.05) rotate(-1deg); +} + + +.button-40 { + background-color: #0078d0; + border: 1px solid transparent; + border-radius: .75rem; + box-sizing: border-box; + color: #ffffff; + cursor: pointer; + flex: 0 0 auto; + font-family: "Inter var",ui-sans-serif,system-ui,-apple-system,system-ui,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 1.80rem; + font-weight: 600; + line-height: 1.5rem; + padding: .75rem 1.2rem; + text-align: center; + text-decoration: none #6B7280 solid; + text-decoration-thickness: auto; + transition-duration: .2s; + transition-property: background-color,border-color,color,fill,stroke; + transition-timing-function: cubic-bezier(.4, 0, 0.2, 1); + user-select: none; + -webkit-user-select: none; + touch-action: manipulation; + width: auto; +} + +.button-40:hover { + +} + +.button-40:focus { + box-shadow: none; + outline: 2px solid transparent; + outline-offset: 2px; +} + +@media (min-width: 768px) { + .button-40 { + padding: .75rem 1.5rem; + } +} + +/* +
                                                                        + +
                                                                        +*/ + +*, +*:before, +*:after { + box-sizing: border-box; +} + +.toggle { + cursor: pointer; + display: inline-block; +} + +.toggle-switch { + display: inline-block; + background: #ccc; + border-radius: 16px; + width: 58px; + height: 32px; + position: relative; + vertical-align: middle; + transition: background 0.25s; +} +.toggle-switch:before, .toggle-switch:after { + content: ""; +} +.toggle-switch:before { + display: block; + background: linear-gradient(to bottom, #fff 0%, #eee 100%); + border-radius: 50%; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25); + width: 24px; + height: 24px; + position: absolute; + top: 4px; + left: 4px; + transition: left 0.25s; +} +.toggle:hover .toggle-switch:before { + background: linear-gradient(to bottom, #fff 0%, #fff 100%); + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5); +} +.toggle-checkbox:checked + .toggle-switch { + background: #56c080; +} +.toggle-checkbox:checked + .toggle-switch:before { + left: 30px; +} + +.toggle-checkbox { + position: absolute; + visibility: hidden; +} + +.toggle-label { + margin-left: 5px; + position: relative; + top: 2px; +} + +/* + +*/ +/* The switch - the box around the slider */ +.switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; +} + +/* Hide default HTML checkbox */ +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +/* The slider */ +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; +} + +.slider:before { + position: absolute; + content: ""; + height: 26px; + width: 26px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: .4s; + transition: .4s; +} + +input:checked + .slider { + background-color: #2196F3; +} + +input:focus + .slider { + box-shadow: 0 0 1px #2196F3; +} + +input:checked + .slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); +} + +/* Rounded sliders */ +.slider.round { + border-radius: 34px; +} + +.slider.round:before { + border-radius: 50%; +} + +/* +
                                                                        +

                                                                        + + +

                                                                        +

                                                                        + +

                                                                        +

                                                                        + +

                                                                        +

                                                                        + +

                                                                        +
                                                                        +*/ + + +/* Toggle Switch */ + +.toggleSwitch span span { + display: none; +} + +@media only screen { + .toggleSwitch { + display: inline-block; + height: 18px; + position: relative; + overflow: visible; + padding: 0; + margin-left: 50px; + cursor: pointer; + width: 40px; + user-select: none; + } + .toggleSwitch * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .toggleSwitch label, + .toggleSwitch > span { + line-height: 20px; + height: 20px; + vertical-align: middle; + } + .toggleSwitch input:focus ~ a, + .toggleSwitch input:focus + label { + outline: none; + } + .toggleSwitch label { + position: relative; + z-index: 3; + display: block; + width: 100%; + } + .toggleSwitch input { + position: absolute; + opacity: 0; + z-index: 5; + } + .toggleSwitch > span { + position: absolute; + left: -50px; + width: 100%; + margin: 0; + padding-right: 50px; + text-align: left; + white-space: nowrap; + } + .toggleSwitch > span span { + position: absolute; + top: 0; + left: 0; + z-index: 5; + display: block; + width: 50%; + margin-left: 50px; + text-align: left; + font-size: 0.9em; + width: 100%; + left: 15%; + top: -1px; + opacity: 0; + } + .toggleSwitch a { + position: absolute; + right: 50%; + z-index: 4; + display: block; + height: 100%; + padding: 0; + left: 2px; + width: 18px; + background-color: #fff; + border: 1px solid #CCC; + border-radius: 100%; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + } + .toggleSwitch > span span:first-of-type { + color: #ccc; + opacity: 1; + left: 45%; + } + .toggleSwitch > span:before { + content: ''; + display: block; + width: 100%; + height: 100%; + position: absolute; + left: 50px; + top: -2px; + background-color: #fafafa; + border: 1px solid #ccc; + border-radius: 30px; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; + } + .toggleSwitch input:checked ~ a { + border-color: #fff; + left: 100%; + margin-left: -8px; + } + .toggleSwitch input:checked ~ span:before { + border-color: #0097D1; + box-shadow: inset 0 0 0 30px #0097D1; + } + .toggleSwitch input:checked ~ span span:first-of-type { + opacity: 0; + } + .toggleSwitch input:checked ~ span span:last-of-type { + opacity: 1; + color: #fff; + } + /* Switch Sizes */ + .toggleSwitch.large { + width: 60px; + height: 27px; + } + .toggleSwitch.large a { + width: 27px; + } + .toggleSwitch.large > span { + height: 29px; + line-height: 28px; + } + .toggleSwitch.large input:checked ~ a { + left: 41px; + } + .toggleSwitch.large > span span { + font-size: 1.1em; + } + .toggleSwitch.large > span span:first-of-type { + left: 50%; + } + .toggleSwitch.xlarge { + width: 80px; + height: 36px; + } + .toggleSwitch.xlarge a { + width: 36px; + } + .toggleSwitch.xlarge > span { + height: 38px; + line-height: 37px; + } + .toggleSwitch.xlarge input:checked ~ a { + left: 52px; + } + .toggleSwitch.xlarge > span span { + font-size: 1.4em; + } + .toggleSwitch.xlarge > span span:first-of-type { + left: 50%; + } +} + + +/* End Toggle Switch */ diff --git a/rooter/ext-rooter-basic/files/www/luci-static/resources/icons/lock1.png b/rooter/ext-rooter-basic/files/www/luci-static/resources/icons/lock1.png new file mode 100644 index 0000000000000000000000000000000000000000..0e650f33a4091374ff1970c47c8ef148269ed47f GIT binary patch literal 13833 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 LNkvXXu0mjf;`?Qb literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/resources/icons/unlock1.png b/rooter/ext-rooter-basic/files/www/luci-static/resources/icons/unlock1.png new file mode 100644 index 0000000000000000000000000000000000000000..0839da5f9f3bd22d7294abf95c4b96c5a3d00bed GIT binary patch literal 12460 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 literal 0 HcmV?d00001 diff --git a/rooter/ext-rooter-basic/files/www/luci-static/resources/img/rooter.png b/rooter/ext-rooter-basic/files/www/luci-static/resources/img/rooter.png new file mode 100644 index 0000000000000000000000000000000000000000..630f30d523e51bc1da06e9f06fe24e1327e1968d GIT binary patch literal 4644 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 a68;B0zfK%Q zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3;ek{r2mMgOr1Edev&%fV=-9ccMF7nvlxDXJws z6WPs5W@SYLe7J)Hbmu?*{knhSS4+veTw1SItLIm?Y;o|S`_He>*WmN}^Zgn>z8C)f zzDxJ}jmTSxuj%vGdcL0@ykCC(K+E6v=ilFVZGErPzZd#`*wp>RKcqW%`6@B5+rId(5Xe|@6x<7NE&H~JzkfBp5B z*xkGPz2~#Kkt>m^?z<@ey~KOP2f0X2@5d^?8~+zxxA)ul-C5!y=$mX#elHg+L?U}b z4m*r+!+Bpc7J;FU-|v>Lieh4Lr^g5CssUHQ~~lB%AEe>QzRtZZ%oUJ@B8h3 zruEk^B{q@4^1|F%;PCTviCMz0+Db3aiO&_Eo&S`3X#0BsLd3lb4?`{I;A==F)Zkl; zEd=7&$fZcJ3-7bB#LwG63yCPHrbcQk4U&~}p?+HK z)X*rYWLHY5rIlW+jGAh$rPkW2Flw~aax1O2)_Suxdg{5CUVH1kTOSrJ0b#|eHD}$- z#^9!dOAmf}@QE>IoN4A+W}R*JX>%;fXXRB^U2XMcYwWnwru}!_&F#Kzj}s21bn+>u zo_6}NGcL7u)6KWsdfV;S?)aItZ&v@FweVZ!{yA&mn>A%Dzt6Q_S>x^2eq165PKt6y z#$pa+yeR_|bX3lK4>?C=PC4@yX^IlbS}01+4$2rA%qPTh!_VCP%G^KZ&6WIr%3J*J zGUt@K|BuW$rS6-#|C+ZyWNnYfDCs3gU8tD)bOAO#aQcXSh?9POog-g(qL*@4DJS|q z_9$h-8zO-+&N(&o3s@CDmILNyxK{E!3zoHW8n9NOxoE^Ct;9NSAB~2YETaf1!fL1G zb>r%R40V9cm3Z1TQP!bF(*eWUC>2Z=V}O8!hyFV;>|77)zkc;RY)5EbKzDpi=~PFV zowImMTQ!BUZTWp`+HvfeZD#7?*sZ|tYV@s(gKKlAYGsYwPiyyt zLRS@8!x>Stq&4MWCZg(Xch1<}BiE!*lsU5x#0{B>1%;MU}n%HaH{bcKlw1q&kv~f4Y zI+Zi3^y;DRqEWyER?53Qy+8NnNm)hN*|m{Y8KvzxE(Nzwin$xF>rJ(p54ufjCpGGh zQrh%X9>8a&Rq}%H{hD)9*(K03efAx53yRf>QDxgHMV3_tj2+g|6U+=U+z8sWyltj6 z`n;QR<}utpGbjXcp4b}&L3z$}1S<)A2}BYQf#>KvI!i&+4ET2w{FLP^7a2ednBY>J8cTPHBLA;{bw6I*K{osaM2L21 zgQTEjXYU8(eDz6Ao1UQ~nUtbJ$57;GDB!0%`i3T?F=M-)L?mlz)R~*ww$o=+8wn<+ z2a7@Rm)m@pSQRdh?e z(HEoib~)MgJyQpJPeY!7)YW(%3smu{5K5$(QJ0O{gUHCrOfV4L2u9iHd=z$^lowE& z(`8!ka9gP*8OqpfZ*-nhA3pYo+c$TVwi4p`!e5?lw)#aMTx zs$=MMV6f6blLjIoyNwR;4J?J-j^uA7jGkbn0uRZH9NwO2;JrglH`V}<@*a>iK$sOO zK(sR}=DKtS{8}%y*vBn>f_CbWGg;csD2O(P(Y$+FtJLp|1izp&AbYNt4ALSp^%kD6 zTv~LAPdL2;p9oGfPSv`FUJeJo@M)wRHR*q6HM^mdwr)`dWhKrvu0 zSxE?i(dnrhZ3+`wi^^#rWuj4?3$)E*XUKcHBgOgnjaQ*K?p@ z?uG26Ugi|5pSr1ALKhdZmzCO?Cpml2@B|w|MjdCOWd-P>ZE*G=YigHKl#DGT zYNJ!E>~k=oM}~9aGqIot=`_nneA%QtFK|j7JPHj!5#6sVFLdLHWAa&~I|Vrx+Np2I z0zC@Pq0In4`j&2yny!}P*AVV?spf`0qE~!USdlq1Cvw`JKAiCVk-Y5|@Z%kfkd`5& zOPUN+gSO;8C2yDWaLYmF)VaZ5NR5jj^P{{IC0<59#9~Ua;881iiwz*pGtn~{z69U8 zT7>6hCFqlRBp=iRh5YgKc#c3v38a(| z3lvs`=KBsNZ(>5y3Kl}P6Pg9|Zt4JU=aE?c*mRcPZnCa?E@}t~06>d{VW3n8E%Jol zLiq7!7jbtU8tCM*nTEvSTwqN#dYmwg^6Q3mFd8~u2#HImAkd|}ZYGL?M?5+Q?i$G6 zF;UTCHh}pK^lqVPL~w$N@1583}bzJqPkc zt5CTp*NaB6QLq? z-J@`@fF(789EkdLaM}C}C67}Aw&ekkt>`igN5KzGRH_Uk=^=)=Rhc%V3}j3{JP(K# zLXDXNtp{dJ;oByA(-aBd7OW(FMGRde0Sq@>M6o#_PK}Bp4r;nf zH%2-YT?@iCX=}h5=ty&w88nN%lCz>(R0E`nEyM;&H5?|#)E@dd=kHu%;f{2SsV zYb3c5T6o%X5SG|4q}0J-5k91+46{Q*joxI6Za%rA(eFALFocFPkiV4ypd9xx{8QUy zAU`2wGo%E19I_%^%Nc!51*jz zB6sOvD56g=6TH&E7qo>(BNuTDHEw7)0s#!c>pUv17uZHhpt%55L!QmXZQa&dPz;8n z!Vl16$R5fSNe{4hFgNi4t!hy*j zWmEHlG0-@-3Ni0G@iuQjf|Pp8TRQNNFr8OgwTj%ArVxD!8x%{d-T^8*wN3 zi_xM=P7eM!2o}wUq?-kZElKc)e9jBS4OsxtSK4dqxoFc&QBbWI)C#>7pcY4is~uD} z-XQ`XVLwo!ykh*w4A!xMy67iT2Weha`Ute#`h)}qp3}f|7UD^N$6V}&g(#;d76FW6 zBJgh8+Z!}WrAY!Jxu59KBna?bhZL|>A8EIXJ33yP$4jzd1gYithsn*KzMeG~(kp~n z5({=h|f)_Fqaxh=(- z9E1S0G-y%yA6Q_+AhCEf7GBHbSYiUpcFjJ6*7z@pNd!c|FwN{S8mJ5>8IvBd3sI5L zK+;}9LHj`2C*{D z8CbV$-lc<4vzOqZYCkg>Po{z7@iL(?X8jQMr&-=V_jn*U3fxOxL#Z+X0Rh>sw`L&7vR@uZ!F=ei9FMsh)%!_ z(Me0ybwy>JbmM3EMS`g?Kx3wcb+GlB}H*#LKt$nP4S5g2rQmyQ(Yc?kNGz1BVxHuBfz zC+9d|dW~9`1qcWqXJPReXoJ9ye9;gc-A>qWvMG5@0f)8=u0jM`)Hg%v%T1P51N(a9#9HrQSLlBLZFd#{945YD>ta>7M&_Wwm8XA!b^I)UsNxvhh{04 zGC)u=-5_XcTg(Si=NmOY!BE)M@Xrw{lo+a9Ljk~HQ-o8dH`9_Av&}QHV!Q_|R3NKN z60zoFeyYm=K)%_E!?XfDNTQV&4}fY73D>OAVneze!lRuo(9X9vazdYx5%tMREEiS7 z1!8pEkozMs@Tdk-V*C-J7uAmIUrKm51sDXAZe|@xCa`z#pG!Qc34|qI+$dNk#1v!_ zspcdYJ@CGy8z$WlCJ-S+fIw+M)d~-yK0y3U5J4y}d^#ZH)Fg(s9C#rZbkv$=kaNXO zqaSmMl=<99f5_PjRhHK7i!iDkjR@*<*^mwXYGDwujZn>zO$!>5YwRO`rI=97P&HDt zeIe|JcOo{0#%M1#P{o96Yr<=y zq$o(t>}{Lhy0_$!f58PefLPP~WoUMCDr-P2U82VV3n9h&615oBLbYQBfPazWL9`JHbUQKyTehjw;xvT|K{29E376md%3H%gmDqG5 z2LgFh8nhc_8&@@h{2V+0I}@0N5OnBqOiY>)nf;wa0rN<3q?y-@N3wlsgqcvRBy{p{ zl&|5eS(K4lL{81FcR9b|6V1$$rh&v~HS&tfN0e(QgOBZ+VjlSJjcsXWgV&E{rrJ=^ z(3i_mo{9d?R};e!%0~ZcutUWc?Vz+a-;j-d1Ux_(%_I>lXAEro8Zw$%8vKp;OA%UV zSZmyC0rP1@$zXIWfLuCsrs*k~5JI?QL~$+v-qB_r>hMh9yP0!st$ z3!Yi7r6W+4YDtIWaN$&+uN~KcW);mWe7@3zjy)AMPG~)r=j4@}h8|$LHW^uX#UW}J zod1fvZhsHsh)d*nC3@dKJHCw_sAizEd< zfZ9Srp^zy#9J?ewD?|Ki50{)2fEiBi+R!LIb$(L2Vj#Vw5Yl+zxFuFpFLzRacGoc$7SC%GS-iqtgTZ9Z2`u3 zNpu1RX*|z@$fWwYTSSeJB&d`8A_3AxZa27|N2LfgkHL^~4Z!fie4}8bOgb1~w>Q?< z;$YO4E|fBW?6u1qwgyX(3$azXl3ViA0DJ=l>0GL{07y4$G7i46Y%vVv+Fh4uMNDbi zj4udPC{07>Q?;M0A4jzsj73zcdXiuh%smKSyhpkWFNdsIa*ya5a=LM1+3*s3VGckR z4ahtif+Z|S{7`}v5dDwF*Q673PD6B9usX@Au1!2`A9kcGE47K6#=YT!yw+>n3><|W zjtz1KMJZ;;IdmkLOmh}z0ku8K_W5AiDFWOvyALBxQ@<7gI`aaBoYY16baBrAtA)k@uW*52N;F&Lwz67B0W6cjzW{stXLOUaPG*ybZ!CpJVN|v&adMx zO@rB^<5{$$$5sT*WoYRwJE~0$=-L}@1GnvP0jFj(R3~Jn(RHMWSjDOYoG=SwO=NIj zM0K_r2k0ey6Sg_aYl4MhlU!Qbl?4Jk42AUz+GeRqd&??7B-4SjsBDCTy{hwdBv`Ek z?eGLhYdd9`pDS_YyYMP<%R^#bbUsflXWXy$ITF~(&t4dYOwQd4S?rHu`E zN+hEB^3wi`E~7(TbR-J^e6HrmLOm9Qf+s^fDZ)ceGrk=*=OMnui!5z)z%v4e2eX6{ zLTJ^gV*)&hZAA%P9Fm_P|3dI>2+0Ja+BrrV_~&|87WCpZ6?%MBlcyob1VnqHqw0yO z6cM%yO>%R8ha@fn8#&?dQxXuc4{Z(xHEye2uTghn`LB#lA}-4?C{ zfC?bdkeUf1)h|2)RuZ}gbWH#)3fBNArgK2#1UBQAb*KP(hH+p7jGwMe6T4?_#2Ti} zxu^k9QXAs~X|}`S(Au|zb2Xobp0wACA^=e7^(F&KH_`p%cSUqX$1S51-hQ(;ZJ{GZ zC>#wMHRh#LBBi6FiR5`mR&^c>#lfTE5fBj=QM8ChrzQB%yiHn|{M zlkWv5cGA|NPVB@DCnATC&BJGH&S~RG8W~l6Xud|nT~^t_G(q5Jrv@UJ!&fWS-6vfJ znm1{-Hz&^^qK%{(h~pXPVx(%7Sl{HIqUwhCIWj@-z`>*#3Qt71rWmuX%#-1g_ADI& zEagp7-n3zAqrOEyHR%yRXi$6VejQ%Hn&wc>nlPr4imDe)4fH}CJCQW4mrrs>1-fKv zqQi#e1o(A9YJI_~0*vG^1r!36KQJhOSKlgLKlPj#7mAdY9LPHDkKm70bI47h#UX%35o8vssXvmRhcTF&6dpAD)kdS3CukBIkxAPnoyh`g zJrFanM4~%clAh>h>>0un&;QQQ=r{~89yT_oon-=e9VY^vGByi}KIoc0g0@q2o(4eK zi%QO#<39S+nIWXpF{oV_pou>;tao*sBJ4ig(V3P4g|C+*O>Du1pk20!Dr#LyuxrDA zhelc(wu?sGSe*mHio06qwK<#{ZetKXs(8jJaLqh~f7St7RhTkBF7_qx~!t~iQMTANTr99w`jozKEHd}ip)jyK zQQa89C?CQ^=2NgOMSO-F0;|=Ij?Q=JlnMVyNfUnh zVHqS7Zm(sdnK%?CXk zA=` z6q+>GXbAS7xE9v1paUnEeQ7HS9}Nqvp`XJzRM*BF!z(@W$y4zi;1ZE23Cz4O*-@h%=OWWIBz zM5i`5v)cBQi%-WwB4PABNmw8`C|_++#~q0##tpB3F44DBM@`)mWi3I?(Agt)aW<~9tX+P)8STS8q zyT9}$<%uAP4qHn5spY4pp3M}CDNhME%DGz761KJ_gu5Di1D-5k%T(hfi^t zv&D)&9XfwRW6xv)N1dsWh7NYoc}4bl<7Sc$i*tA3$rhx*Mq}T4Shk}C87g&1a%j&#~&7}`wm1_j_4#|rPz3|5hZXEe9Y?*ZaE4d45Sfdb)D z`gbo-cGq^1Ps7QN0kbG8B%wx<;s;Peo5$m}jRRfCtwBWL1R{K@j#ji%F*jg6K=P@4GKsr-lF4U`RFu-N&`A?PFwEuP0-FmMIFS& z4;0F&;#ui5>+)_#(+!WVl3{9@f=k+zpEMwfgKTKRj%(oi^kLo;(nOr&+ys5^=nPSV zvHhZfz?Oxw1AJ={(8AC9*B0n#jiFKH3%72PwR7v#&+u&#&^@JqKr-#8qE(TL3FOy4 z8NM3dKyAWk+ApM?whM4~K+VbGzUo7Sk(K5(dyoKRSzUur!0DvltAX2otHFKB!RxfA z%0bl-{-)}Q_f(tdWH1Pc4k#KcVwFna~_d32+qPDaq&RGNyC=y13!i=|8{SDjQx zYLhSFKfa&Rg$Z$pI4;1S$mt(U!6HH1UTHkr#*e{b+aTwLC@V7J)Wg-$&aw(?Kwsg? zvi1QL4qTMYjlD&UAkw&(Ft*8)6`i7lqMxf%&q(e|l2#hgYX|a=o{nH|Zgl3>-ctwC zi1pJ!AH|Q7g2O$Pb_seAkpB|=88G_l{piTH4mFS?U=b6`vI;*@h1G*<0@=Nx$|J21 zW2Z8tG$1Xnf7LcUR9>;T!$}jMKDPcoA@J$(0f@1s&m{OLzL_+RHAVD6HN`M(8V z7@#iXch^Hz0-6{DO56N3b#ytokO~nrq~K76V%V;!7Ii+u0wq4e808s!f^Gm?KvYl_ z;23GpBpeovMw5cVB(U0m3i}6-1#tjfK=5E{Kn(;RG1fv-5CW*`>iecV2GfuB`40!< z_Wf~PY`(dG#;XH;d^r`b3UE3Q*aU>Q7ha`ze_LM$mMgPg1}V?+!T0s_6$PZgdVRs_ zq``YnN{OOal9Hw$L0kCnZ_cj0>~n9mN)`DM2?_;$2dh%<6$2Dj?lBA_Rb4`YFaJ33 z^baf0u<6fP)(Zf}ZBN-O=`VZg<>LARRWpnB`{Uaa&_u{%tpK~1*J%RO0C=E;R2)r? zXpwOkD61vg&e7Bbmupxoz&S8V1c!Jepnx*q4WtyPOM?btikO|Y)}#d6Eqwf|v&X*Z zi?6q845GYU50!-!Kq=9dy@z@!=Z?Ws8;cKM4Jaa-i1UupR*>|5?V7wuRhL(!0V;_4 zV2r*O#D7}>oy?hzz%(%hr0T%bc@lv@0!kt>sljD!=Hb`BJp0OryZxY50Vp)M5$X!G z1~-5YuxOy)LQ}}!`we{h+p|CErJsAys)V=)D(;PQw}q;KqJZeZ7#KUK>*-x1u-+}y zL=DM8k_GU+fPQNN3Ms2hHJSM<8q|a8^DmWX(6raA0f$Gi4K)OV_VC%?oqeMRy7PLg zl!0-8#S(O${ELggvN0Gfnk|Y~!29ogv-<(ueYI7TvLK3Dgw7ngGK#!Vo%q&NdBMu_ zeJ`Kis(>E4Q&G&DijZQq$3FX>#oh;1fO2>W2EYY5?YHlKb77f|m+y<9c0H_4L=Zv> z7@csTC#8Tkw+JI#o=c4O$w%Mp{&#=Ys*psJ_MN9JEk*W`BMunznWYG5*1+Ej=(j1L z`Ri)uQ@Vq|$!4vo_d$``2S{Ut%?3XI`+q&bye6oxwn|y?BQdb)JC=<`;RvkQUV={W z={J0aSKn+^&|vM5wWVlDjXek`!$H7Ud>J9xvQ)l`Z$aqs?kC zBv5)pXP99aM(U~oEHQdQbQIR&Tu)Jy2gdz-9Q1LA{YKKAgCue0nMhJVm@W39CameYl@QN{)fN+ z^U;-fHKjJB2-`~uphho&Vp7nLUXYCV zy#RizQT&xq9z;dPjCraK2zUa$yM;}EUVi6G_ghs~NahKMA)$?g?wf8)-7I!~_~mxX zYH`YT3w6%nKl%gw)9>VcUwXY&MJ?mgk6*AX8(=AUjPL!=uTp{jNTKQ*{7gMBoQD`E zG3Vcf-60gY5`{3({%nNvUaQJdo>?o=pfM_vmaLa87Yw5eiM5v1VnyFWUBU-{dwmfa zV7-B6l_<*^Po(S4IcaX8rtI5+Yn1Ys%c$!)&*?aY_gxmy{$LpG)xnyy;z5Ev9dkYv z3}d9KG%91PlQ%_Sb zNbUwdD#EIP?U*Rb6^h8BNhmy$T`C}IoC8~dSBb!YLZdPwk}@T=P?=wl_Fw%j3#r{N z!-K5wEc_9(OzJD=gaB13pQV)OgQv757neP&lM0pK;otnn7tXt{wMv)Jjj&pQ8zMz1 z+<_3q7yW34D==KbYPmo;@w5N;AGhj%{P(NptuJ9^q12WTz&p{4l}VIEwl-0VuNxsL z#o!u>3Suw5YF!KUP%Chwr?3|O6U0~+Y7!cS7MaW@MyX@&@${S9@t3r+SPgN2A@tOX z0%Mnq9!^dQyn{6S#~y&&4_bv5_8STorM#o5)@%n)ZT|u{+)VxZ?FakMU%A(+)2FYW zQ#B%JA03=~=RvEqQ8<@rdSrg<2p`T^o0lK7$|*<&iYhRy*Hp_@W^8|VGf_Gvfr-+Q z7^W+Jsm(5cx?=1V9^d!q0-A+Esf0>kwPafeUriMLcNNZw;8AQC{Qp9+LE`|AA+o3n zdF?0ARIlC@QcCaVp^^_ixH=9Wy?d5|18obOx1t!!S0BTt>4GWsortr-GnUD0jevzf*A{JmB+ISuNf{CxbkPyXI_ zf7YrLA#C8`0p0Jpw_4$VZ{X7d;ePe)R{79TmzLl?##Y~H4QjtiIQ5ZQRS1@+c7qZL z-5S$0_^9ZIoK5lnelPXH-BuMAiUz!joNupBU|C2;DABVlPh=<(JazIz01CT@k&=RN z)A%%i-T;ovbxFNgTs!Bv=USyspm*^5BTd>3QU&nvh>Pli1WcbDo$nnKb;CIJl;w9@ zI03Al;2|<=m~bGm7DaJw5O(BbETkV`s;40-j4db)oIir!e+5(NnKxSX`L{&1GnxLk zegyT?n##`Ow}t^QJbHA=Q@1LJ!o)9YP}<;Ak2M7W=C48KW$Tg{mfULKd^7VrE9eU_ z&CCQe^TPk%Zx|b0L1d&XYyLAFR-lfAu)QZCJqYk8-r{jJrsx^@iiRO)N@9Ava6b1& zCJ-BVv29h%xBlc`$sKquGmk)+^p~48#bR~koFBj3s?tCTJ<2S2>Zuz30-;`u1^NaP>qCD`oK)S!cu~*GyNQ_d6<}F)Ea@c@#>ZV$nPW z!Q%Q+l0&6od%4*;rDHb`U7)HJLBYiqoQKaI1IGXKUaPDX4Ws zJo{3s?!M8gJ8!h=*;l`wz<%`JSsMGS+H?&p2~M=zPNRifap}azL=9KD!)ouM8w^_A ztf^`P!Br?N3vd0!^>ez5!z!d>35U&vls#WD@$a7{w}sfr&&ThbrC;ZFi^IXOHzm@=Lv)vv z7EJm9al4|@B_=^_5``9S<>^T#QW){ko_YQ23F(KwIuq;cDj2|c*q&eYQ6~pSq_hLQ z2GfBZr0Yj2fCVX8tcqw0fBDk&=lJLsXX%4?&JsbA7XSG9^>Mhh0P982u4&fHX~uK>UkuO4+Y5V2F(Uz@l!5KA?@+r&1Hd7|>P` zgF~y5z6;cq#d)#Pqfcn7=sNiA*AURVcLhuQAW!)1w_2qX3|n~WAa0VP(=IQNYEOd6 z8Y%>7264HOTKjkq!J7nqFV*ggg_atFTu7Ka7za%)*YXOsql}5~p{a7`5(7y^Mwe?q zGbt?O>uW0kQdP-)y6%$2j!RnejSD0GBMWFuYoKJaNiw(k_Ip8q6ID*kh#2K7? z{O|@SnM1hSfXaK!;_G%+e+numZfDo0@kq9%AD>=mUYAQKkG zo9{a-r1x6Y2dRlNWp1hfSnsl3)fv~#F?O(55ep4N-&0kxI0v6ldL)?x^Y`VwU-Ok8kr2`9I}1xH~D#&Mu3rM*s! z2BR&Ia?7B_cUyyYE@F&AMYyt^dT$V+*al{zkD(weffcy&p5G@ z+=kj3Ds2efqiwM>?&?}^shE39MewDVl_UXSk?}~E2CS+vQApcCtr>`DP9bIibsj2* z4+GeS_29Twt{}>S>9&q$WpKWyumuUlW;@UVx5LKF~v#2STCij)#QBur)iD@Q}7dolvSIQjwg-8g{OZ_YPAA5H@j>uzjlUMJrjz5ZrCO$}S zwv;is5q|ZACiKpmt(s^g6GWp9$;*?2cl01hO+u(qsW=jf3Hr&{YdXke?YOBzt{_N2 zM}iM-(5TPdYn9IMmSKaBTMAv^hCorBN(a0swp=NR7Ps3=nx;bOM2rJUgThEKIaREx zK=K}COL^#Iug|#xb*1HvG_#PQ$ilYkUg<~-c>ppfm8N%|7HrD*ulAh+kK0?$PJEmf zkaTtEr>jJDc-C>liR|~J!#TN0K-0{iQO7h+bdCIP-)D0?s+=LImN}&wCj@z>Pn8~a3FI*-c;knp=Q=s2G<42W@+X#S$E!Ql`dfP z=QQ?~$iJ3%tgKXAni4`xq!hAm98kHbs)=tpSV(T`h{f#nLc>d_1|g$11S2%XgQG12*&aJnl4n)2FA9CK0i_41Nk zuGQ~Nf&y&=wip94jtj|VS!{IY6p){j5d`=+?ptWkUdU-0k&;*mlaQ1lsQbJ_KX zN9#&oUvyWhc=goh-*SmCEQ`NwTQUy>FgQ6(1 zSsx>1scA}^HT8JK%ZNMAMS>u$s%s&mnzZKxp&YEJcp%28ye#urA_~+`tbfTCHHkh$MI~^`X6;!nb7La5B3!Oy@Q%6(BnrVRZd<&%}FW+mGDW>2%ptZwd_nDk4!QP}@ z(m`aNCqd=>KL*k=`xjHR9*@i;SEA>1BR5yi2y&c>rp;ALE3g&(cZyfk>f#@aE@&}qI$7MPGT zBs&3}+AtP5`qcZ}CI*7$AXdu0s{<~xh7gmlufQo?7SJl=qY%AEmlp4GQeh!^d>sWJ z*O{88BAj2qRMa+P=Krob)xjt4f3;A*`ev&}57M{6=P|W2PX82@PbRQ9&=!-aEDi*e z1A#u&bdwo&$ksa56?jUi$KjyI0;;b^;$cRsAC{V{uM*IM(&@QfUal>cBh49SeDZ^5 zQ7P9XrL=#?h)k@H;)5*~G7vs^tUYqr4=h^OL9@*H>pU?gPo5hj`vTB!I_joj=n~aZ z?KEUJd_hws(xgGt3fGrZRTehuuzDl}k1;32Aqf~^tvG605r}LZRA#?me2`5R^tAa# z5?`~b4@ffUXfD(K^+pH3`PEr^?Psm>PToUnaK4lB-$^qbG_gooIH%?dDMefusjS6C z(5aLTcL&1cgQw7vAxi$BU{g)CUt<=~lbr=p`bh;ehnNAhmL9DkZ}^~c8kt{S^?;2vjXtRUZR2I&ZgVo?ASl?;T=*1C?SwOo^@J%=F zHO%NF&)HOR!Odo5xhNU>L{%%2lljpGoKLtg(ljECK9eJ~$`6sVCl_C?IemJSCnKV? z0~>L1E#EJ05i{o3=VuBoV2t=^M(1t{W6C#(jIN`oN+OCc&mB+QYVrUMd2&5N7^uvO z$Vwo!V-t1k!so4UViHJ7WdYY$pdoW*TbZOH(}oF9?7~5CY{zp7yP(i3x-HZT82pCX z%6J8*&=Ut$9mt4!v`cOzR=X7NlWNdm98gMA77NBf;t0}#p4qvDqF8)CV5{b;A9{dc z$E@wmP9slJWoMsZ+ij@p8m;y&MoI_0uY$;1O8Y&llm-=34;TV=2f0iNWjpjNs*>LK zGYY0RGOX7u44^q*n>&Mv5}~pt&3)?R?1~3oKgt9bP*5@D-!0uvzhTZo{G|(Rd<`f&xXuI3!AY z5G5Y$IhC^OqaKSx9-CFW69@%td#DyNe8ae=E{!nCw8p3k?_zGad)4eFMHbM2x#BY) zcZ`no!(jM0>(!l$0? za3MavPnT>rD?WKbcF>EjXLgVVt0Hk6u-ag(qIZTuYogB^X3Z4Oz4&sg>;hB?hBbaL zSlwW(_=U!Zy6?B}*~9r~`qA^P(zURys<@x5FlD=j3l+kQsJ%4`b=$ z6l->%4hah`1PW71Ezm?TiIaJqX!1?|p5NiSDTrWx@Pr)JXJ2Yny_5{9PXj4l(iFFL z*`;aw9M=SU2&CDiAorL+ zJksF$8tAy~wk(>}-cQd9E<^|inQoW1lqwREqf&L|>!h9-Dn9s{{gZzBpjAz^Uq4f` z1{LOW;>X7eZ%NCUr4h~LomkG~;ln3gEN`_c^f`#j9Owz$pWG3XWUHH1CMb^^Vd@u$ zRl6x3Kv`2~zWp({fvQ+AI!~Fu=*NW80c*p753BOG?T(%phwBXdujH_1ilA0qR$c`} zdl0h>yNXjO3pbA?EvF^mXP%(4GpeM1^vGz(b_YL`^8JG}A`>QY~s!IFm_ z$4FUNh8{MT@Pnr%E0?r1XS>+It*5e~NNY-E=!Z2rQsF(k^fimqrb@+tW9yta>@$Ro zpWINT`I~pnk`8i>t&!ss)UxC$QnN4@3{CgJ1vrEWQ6XXKC07 z$2B;ix0fdoOb=>9;DY@|W4S?7D%khguW->)6sPnqVvCwFcs6~9EtTwUeAttJhZp4_ zNlP8#oj0yO|8sA&>e-*Q>c=znR-1DPE{9>dwmnKvRS1*5cp~bXa}K2h>>%yqf;o2D z7aJ%SB6)6{;G-&+!4yX@nZKUmOjlhD??t-?FX_Ol6ybEE^iuuJFVE6P@0_K7{O~NL zL8@@VxFjS+T{Xf74G}^Qzy6xr5Wd*9N;6=n*gS&IKRgo7S6XFi(IhuDX}J9}srKAl z!sqYLe19oU`8dEo&S;`%?}=G-SqXmp*E5Z`UT#&j1fLSN^mKltuuJLEA&&UY&cq4M z%VOhv=48e_Ib@;0GtrP$m(j8P=SdcAQQJ z=v>VA&GgM3@}1X_4-%7nG^2=a-))tTP_M-AcfnyzzR=fgLU;RTtrDt7u`drfI%+HI zp9I`}y;XC**x)nXHM6R9geHGuRl=QntvY_O&whE9UU*d|`{NrH!H0R_y!2YDC<~G; z=%VD@KRWu(o!47MmGx?dmwbP=onE+W3c3|;j^7X?6keO zg&#d=)$flQSNH>>%Wn?G?b-X%?Ber04!3{SDyu~ReTKxk9zOYC#(cjb%^x0@ZgzWxYMfTNrA=pC|!T;`u|~o+KxmlRRJH(Xs!uMo$%Bb?zHMRM?Hu>|HWDQ z$?L6}E4!^r5u&mTi~|&QKG9xi;io>y5wdgs$qhdDrS%Z{T7Ji!BVZ3dDrQvBHIAP4G&itDc`u}W=Dzk zqv|N@4VO2ld8K5cpZTkKU-jkJTlM3Y#N9~lx^VvGy;ePQ?1MY80CUGb&!7vdMq1LK z0%L!1P%E?%D{(x*zc@=p1pjCz0DYxZU#EgYC3*2qhPhPotP2UMCjPAN{K6B)IfAY~;N(!ERbAFzleZ5sLJZROOw_BA;xEw&E z3n`oU8aqzdykS+MkkZ>5!mIOh$&dYyhl2nB3+hQkK~x6?gm`0n`gC^r}?D$q%G8PYUypUNYAMuCktHHm-22`7Tp6O zw)|)&_;pd-fZGqQ|IL=-)|{VTk0~P8!Gcd8o~7jB{1T0UOwM;*`*DAXdVK*c zIH{Rg9G|=^Zh@PjlEx$f%4){i{ofzVkJFs&kTL$$z@4{S_0iv)rI%lm67Udjg2Uwh zTdSG~tS`3$*eNxyeHN#ZxOncZR((3-uT&}rK@RS`(yF-%%iv(lOQyQXMCqIN3G)0%I)DGtd0Y>#Yh7PHcwk3@j=sckoFQmH7GB7Do+Z=vWx>L$p4f zr7Zu$yJzXyw_0^$S3WflH*GptE^^lRcyYWYO@E70S_#!fZYD8vZs;MFA|IPUP>Ib3 zn$^uazUZ7#FnP>RPZns5ryJ(sG@Z#3H)+UiCbpa6W)$GlpPwb|B|*1c&!7RXwyIcw zUBWZ3TsJwN{`@SB=g<@d$q7a{C!uvUUtsw0J7-BUk!s&saRx2$Av3XZS{*AZdTwXD z%|-6Ml5_q~pC}XsDKuDJ6J6R-@k*@;GZJ*Uh3Z6nY+Hg(f#?SefuUbxnQ!H&5-dzZ zw;d^22s`NplD3L6e{&e@*w2r}qRG7nX5QQ7I3gN2y(NK+uIA_d_rEwxWe2Kqz<#DnN^axSn%2iHl&6z5-X@tDncfA`5*(g`lUgnB9P%iMXNy?2&2U&8N> z{jGb_3@ho8qz0PR{C)oM;aTdxgiqf&OaJ`I)oZ+Zzg1IixxS&NtKZ1`Oaheu=;`}W7IJ}X_=P4?NLq1bRQ~6~v!tU~ zt`IzhHI%j@#-7t=g&(Et zQy(Ay^no;GE0e?xAO8GIYAy}DcyC6z{PHY4{DlDVAHH*z>O5}FXE^Uzo<2NFjPQ9z zQZyEof+u;y-`%ha+})qGDq5l3eR@M89>a%8aB(hsQa<>wFQ!l<8?ZieuT{@K zxcM5lUu)Ivw^|jI_+;yCqAD~dYsi;pzWdVsR$Z)fA~K2gzUlfe-EEckkKY~d{Lxe= za3Gi}7ro)cRZcv%!R$|8Y?VsF2?ZFp(zR~2C}sn`EBF6WT#SgPs3a5j`fIJa_wo%; z+nrY3zuzirB)ICvKU_mDKo+k>k@){WkKBIHs-NDye$6{Cw(6DFS{0)pFqc~??|$)y zwDha_^FlX7@2D$Dyv&h_?mlQ$3=@PlY|*A+(@VxfHJM|%l|aDc>I|Q=8!<^R(Ug+q zSX#JP!|Exi;tW{E?3aG|B|P=CY_D=FN2L?_H%g`Q&V}gxmlS19qG2azn<6^@eS~p{oBY z>#g{q!zj_cnFJ`x{axDPOi!gwFg^zYN=&z3fK!sj-JHW;oC;nV1L!6aRL9ya`RqvR z-M!x`-9S|5Xe@yxG55uq{6}k~->Fj2<;@<*f7dy%H50{mY7y^*fHDz+%0hfiQ%X;; zsVD5z2h67q&4AUVEY+gPH&CEdN409CFZ$rHO~HCQQY}i>!zCwmgCSumVcMMDlFl7P zS)fyt3lsS-Ps`Iib(&GMB4M~CP+F0-+2rIWjT=U)s$o?@WJ_Z_4$q>oXevyp(77a{ z;(`d&%`MyrWl`nP@OT_9oKu<#rB_7P3AYsJhmK{nkX&P?t(j7z$|`Ha$mRN+X03{gi>1OV zxb;Jkg%mwnODRc_SzH!+5(*aIDjkvI`5|D{NtLevLMfrTL-M)&r+av7?2ZRFN1x-3C^xhNK+bu%W3c#&Jzd z9jB{?L_tVeYL^<&lz_uh5GUMrB9N!4F_i^XUFEQ=k@NK*d3yD~0hZ17lEvag$^s3n zhd;8YR%jZc18oWl`!ocp2SW+FNGoZQVU)uAErlsS8BAIVEHgC&G#yE43Mw|^NK=Z1 zD73~dYCi%K=esKcNJ;M933LRTRcYfbncR( zSdvI6EY4|48k~bglY6B^kJ16>I;x_;`H_I8v?px0y)1b}+Tnd;+%QO!cWku~Z#pKx zQR;vX9R^K-&HkK6YuH>SfkjeIct?&QACV3tQK`9!WURo zqtH}kO;fGdZhI7(m_dF8^!=964f0%*a2~X-x!!hQ-#g{$)hU115JA zY>H+__e(xN7|>eEMk*`SO-7ZJb_q$ds28Xdg1FjRWty%;a5mU|XKVs2dVF*!y+Sq@ zfX(KT#j<4ArOrbfd-R0&=sz7Nj5T!7qabOs$iR)kb}MjA%H2x zN$j_>_gJ-vc8e)9 z)Z@M<>O}vW`l^v4%1n(O3R0?A=hp3R=vY++F?x))Y`UJJS#YsgbFw_8OyJjY?iWL@ zOBw}uweA$A o&piNQc9V3j?aG()gSZ0!KLh6sReP576951J07*qoM6N<$f`H8iw*UYD literal 0 HcmV?d00001