Merge lp:~cpe-sa/obinstall/obinstall-cb into lp:obinstall/next

Proposed by Craig Bender
Status: Approved
Approved by: Scott Croft
Approved revision: 49
Proposed branch: lp:~cpe-sa/obinstall/obinstall-cb
Merge into: lp:obinstall/next
Diff against target: 3100 lines (+3022/-19)
6 files modified
00-network.sh (+4/-2)
06-juju_environment.sh (+30/-17)
PACKAGES.list (+2/-0)
etc/OrangeBox_UTF8.txt (+575/-0)
etc/colors.b64 (+98/-0)
functions (+2313/-0)
To merge this branch: bzr merge lp:~cpe-sa/obinstall/obinstall-cb
Reviewer Review Type Date Requested Status
CPE SA Pending
Review via email: mp+297838@code.launchpad.net

Description of the change

-Move bridge-utils installation ahead disabling Network Manager to prevent resolvconf resolution issues, otherwise you might not be able to resolve the repository
-Add functions to obinstall/next so we can begin work of cleaning up script variables
-Add functions to obinstall/next to help with automatic bootstrapping of MAAS and OpenStack Clouds
--Note: MAAS and OpenStack are the only two cloud types that aren't automatic
-Remove creation of environments.yaml from 06-juju_environment.sh as it's no longer part of Juju
-Added comment/question about validty of jujuplugins - Pretty old
-Test for sademo dir before branching, otherwise pull in 06-juju-environment.sh
-Test for symlink before creation creation in 06-juju_environment.sh
-Add jq (for easier parsing of JSON returned from MAAS 2.0 RESTful api) to PACKAGE.list
-Add screen to PACKAGES.list

To post a comment you must log in.
Revision history for this message
Craig Bender (craig-bender) wrote :

sed 's/merge/branch/g' wrt sademo

lp:~cpe-sa/obinstall/obinstall-cb updated
32. By Craig Bender

Landscape Fix Registration functions

33. By Craig Bender

Start Work on MikroTek Functions

34. By Craig Bender

New text manipulation functions

35. By Craig Bender

Change IFACE variable to MGTIF

36. By Craig Bender

Spinner and PingWait functions to cleanup current methods of waiting for hosts to respond to ping

37. By Craig Bender

Continued work on MTRPing - Have it use $OB_NUM based IP addresses

38. By Craig Bender

Fix test on $OB_NUM when setting OB_PLUS[1-3]

39. By Craig Bender

Fix test on $OB_NUM when setting OB_PLUS[1-3]

40. By Craig Bender

Param and VarSearch functions along with WaitProg, a wait wheel tool help making waiting a bit cleaner

41. By Craig Bender

Box drawing characters, function to get cursor position

42. By Craig Bender

DrawBox - Function to draw boxes using UTF8 Characters.

43. By Craig Bender

Added code to have DrawBox fill the inside of the box

44. By Craig Bender

Added text option to DrawBox function

45. By Craig Bender

A few fixes for SSH terminals on DrawBox - revisit mono-spaced font issues later

46. By Craig Bender

Replace full block char with non-breaking space character in DrawBox

47. By Craig Bender

Fix how JStat reads beta variable, and color, OB UTF8 misc scripts

48. By Craig Bender

Fix ShowColorss

49. By Craig Bender

Put OB Drawings into main functions file

Unmerged revisions

49. By Craig Bender

Put OB Drawings into main functions file

48. By Craig Bender

Fix ShowColorss

47. By Craig Bender

Fix how JStat reads beta variable, and color, OB UTF8 misc scripts

46. By Craig Bender

Replace full block char with non-breaking space character in DrawBox

45. By Craig Bender

A few fixes for SSH terminals on DrawBox - revisit mono-spaced font issues later

44. By Craig Bender

Added text option to DrawBox function

43. By Craig Bender

Added code to have DrawBox fill the inside of the box

42. By Craig Bender

DrawBox - Function to draw boxes using UTF8 Characters.

41. By Craig Bender

Box drawing characters, function to get cursor position

40. By Craig Bender

Param and VarSearch functions along with WaitProg, a wait wheel tool help making waiting a bit cleaner

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '00-network.sh'
2--- 00-network.sh 2016-06-02 16:26:55 +0000
3+++ 00-network.sh 2016-06-29 14:56:15 +0000
4@@ -60,6 +60,10 @@
5 echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
6 echo "net.ipv4.conf.all.accept_redirects = 1" >> /etc/sysctl.conf
7
8+# CB - Move bridge-utils install prior to disabling Network Manager as resolvconf tends to get wonky when NM is down
9+apt-get update
10+apt-get install -y bridge-utils
11+
12 # Assign variables with the values for the network setup and execute the check_orangebox_number
13 #
14 . /etc/orange-box.conf
15@@ -103,8 +107,6 @@
16
17 EOF
18 ifup $internal1_if
19-apt-get update
20-apt-get install -y bridge-utils
21
22 cat >/etc/network/interfaces <<EOF
23 #Those are generated automatically by orange-box package
24
25=== modified file '06-juju_environment.sh'
26--- 06-juju_environment.sh 2016-06-02 16:26:55 +0000
27+++ 06-juju_environment.sh 2016-06-29 14:56:15 +0000
28@@ -11,24 +11,33 @@
29 apikey=`sudo maas-region-admin apikey --username admin | tail -n1`
30
31 setup_juju() {
32+ # CB - Juju configuration data location has changed for 2.x. It's mow $HOME/.local/share/juju
33 mkdir -p /home/ubuntu/.juju
34- cat >/home/ubuntu/.juju/environments.yaml <<EOF
35-default: maas
36-environments:
37- maas:
38- type: maas
39- maas-server: 'http://${router_ip}/MAAS/'
40- maas-oauth: '$apikey'
41- default-series: trusty
42- #enable-os-upgrade: false
43- authorized-keys-path: /home/ubuntu/.ssh/id_rsa.pub
44- admin-secret: 'admin'
45- logging-config: '<root>=DEBUG'
46- lxc-clone: true
47-EOF
48- rm -rf /home/ubuntu/.juju-plugins
49+
50+# CB - environments.yaml is gone in 2.0
51+# cat >/home/ubuntu/.juju/environments.yaml <<EOF
52+#default: maas
53+#environments:
54+# maas:
55+# type: maas
56+# maas-server: 'http://${router_ip}/MAAS/'
57+# maas-oauth: '$apikey'
58+# default-series: trusty
59+# #enable-os-upgrade: false
60+# authorized-keys-path: /home/ubuntu/.ssh/id_rsa.pub
61+# admin-secret: 'admin'
62+# logging-config: '<root>=DEBUG'
63+# lxc-clone: true
64+#EOF
65+
66+
67+ # There haven't been many commits here in the past 2 years. Are these still useful
68+ # given all the changes to command between 1.x and 2.x?
69+ [[ -d /home/ubuntu/.juju-plugins ]] && rm -rf /home/ubuntu/.juju-plugins
70 git clone https://github.com/juju/plugins /home/ubuntu/.juju-plugins
71
72+
73+
74 # Change ownership recusrively of specified directory
75 # sudo chown -R ubuntu:ubuntu /home/ubuntu/
76
77@@ -108,5 +117,9 @@
78 setup_desktop
79 setup_remmina
80 /srv/obinstall/import_SA_keys.sh
81-bzr branch lp:sademos /srv/sademos
82-ln -s /srv/sademos /home/ubuntu/demos
83+
84+# CB - Only branch if /srv/sadedmos does not exist, otherwise pull (Setup guide leaves /srv intact, thus this will usually fail)
85+[[ ! -d /srv/sademos ]] && bzr branch lp:sademos /srv/sademos || { cd /srv/sademos; bzr pull; }
86+
87+# CB - Only attempt symlink if it already doesn't exist
88+[[ ! -h /home/ubuntu/demos ]] && ln -s /srv/sademos /home/ubuntu/demos
89
90=== modified file 'PACKAGES.list'
91--- PACKAGES.list 2016-05-19 22:40:57 +0000
92+++ PACKAGES.list 2016-06-29 14:56:15 +0000
93@@ -1,3 +1,5 @@
94+screen
95+jq
96 nmap
97 bridge-utils
98 amtterm
99
100=== added directory 'etc'
101=== added file 'etc/OrangeBox_UTF8.txt'
102--- etc/OrangeBox_UTF8.txt 1970-01-01 00:00:00 +0000
103+++ etc/OrangeBox_UTF8.txt 2016-06-29 14:56:15 +0000
104@@ -0,0 +1,575 @@
105+OB_OFF='
106+┌──────────────────────────────────────────────┐
107+│ ┌──────────────────────────────────────────┐ │
108+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
109+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
110+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
111+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
112+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
113+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
114+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
115+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
116+│ └──────────────────────────────────────────┘ │
117+└──────────────────────────────────────────────┘
118+'
119+OB_START_NODE1='
120+┌──────────────────────────────────────────────┐
121+│ ┌──────────────────────────────────────────┐ │
122+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
123+│ │ │◎ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
124+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
125+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
126+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
127+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
128+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
129+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
130+│ └──────────────────────────────────────────┘ │
131+└──────────────────────────────────────────────┘
132+'
133+OB_START_NODE2='
134+┌──────────────────────────────────────────────┐
135+│ ┌──────────────────────────────────────────┐ │
136+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
137+│ │ │○ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
138+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
139+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
140+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
141+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
142+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
143+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
144+│ └──────────────────────────────────────────┘ │
145+└──────────────────────────────────────────────┘
146+'
147+OB_START_NODE3='
148+┌──────────────────────────────────────────────┐
149+│ ┌──────────────────────────────────────────┐ │
150+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
151+│ │ │○ ││○ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
152+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
153+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
154+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
155+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
156+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
157+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
158+│ └──────────────────────────────────────────┘ │
159+└──────────────────────────────────────────────┘
160+'
161+OB_START_NODE4='
162+┌──────────────────────────────────────────────┐
163+│ ┌──────────────────────────────────────────┐ │
164+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
165+│ │ │○ ││○ ││○ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
166+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
167+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
168+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
169+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
170+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
171+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
172+│ └──────────────────────────────────────────┘ │
173+└──────────────────────────────────────────────┘
174+'
175+OB_START_NODE5='
176+┌──────────────────────────────────────────────┐
177+│ ┌──────────────────────────────────────────┐ │
178+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
179+│ │ │○ ││○ ││○ ││○ ││◎ ││○ ││○ ││○ ││○ ││○ │ │ │
180+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
181+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
182+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
183+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
184+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
185+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
186+│ └──────────────────────────────────────────┘ │
187+└──────────────────────────────────────────────┘
188+'
189+OB_START_NODE6='
190+┌──────────────────────────────────────────────┐
191+│ ┌──────────────────────────────────────────┐ │
192+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
193+│ │ │○ ││○ ││○ ││○ ││○ ││◎ ││○ ││○ ││○ ││○ │ │ │
194+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
195+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
196+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
197+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
198+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
199+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
200+│ └──────────────────────────────────────────┘ │
201+└──────────────────────────────────────────────┘
202+'
203+OB_START_NODE7='
204+┌──────────────────────────────────────────────┐
205+│ ┌──────────────────────────────────────────┐ │
206+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
207+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││◎ ││○ ││○ ││○ │ │ │
208+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
209+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
210+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
211+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
212+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
213+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
214+│ └──────────────────────────────────────────┘ │
215+└──────────────────────────────────────────────┘
216+'
217+OB_START_NODE8='
218+┌──────────────────────────────────────────────┐
219+│ ┌──────────────────────────────────────────┐ │
220+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
221+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││◎ ││○ ││○ │ │ │
222+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
223+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
224+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
225+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
226+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
227+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
228+│ └──────────────────────────────────────────┘ │
229+└──────────────────────────────────────────────┘
230+'
231+OB_START_NODE9='
232+┌──────────────────────────────────────────────┐
233+│ ┌──────────────────────────────────────────┐ │
234+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
235+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││◎ ││○ │ │ │
236+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
237+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
238+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
239+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
240+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
241+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
242+│ └──────────────────────────────────────────┘ │
243+└──────────────────────────────────────────────┘
244+'
245+OB_START_NODE10='
246+┌──────────────────────────────────────────────┐
247+│ ┌──────────────────────────────────────────┐ │
248+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
249+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││◎ │ │ │
250+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
251+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
252+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
253+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
254+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
255+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
256+│ └──────────────────────────────────────────┘ │
257+└──────────────────────────────────────────────┘
258+'
259+OB_START_ALL='
260+┌──────────────────────────────────────────────┐
261+│ ┌──────────────────────────────────────────┐ │
262+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
263+│ │ │◎ ││◎ ││◎ ││◎ ││◎ ││◎ ││◎ ││◎ ││◎ ││◎ │ │ │
264+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
265+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
266+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
267+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
268+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
269+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
270+│ └──────────────────────────────────────────┘ │
271+└──────────────────────────────────────────────┘
272+'
273+OB_ON_NODE1='
274+┌──────────────────────────────────────────────┐
275+│ ┌──────────────────────────────────────────┐ │
276+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
277+│ │ │◉ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
278+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
279+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
280+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
281+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
282+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
283+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
284+│ └──────────────────────────────────────────┘ │
285+└──────────────────────────────────────────────┘
286+'
287+OB_ON_NODE2='
288+┌──────────────────────────────────────────────┐
289+│ ┌──────────────────────────────────────────┐ │
290+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
291+│ │ │○ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
292+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
293+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
294+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
295+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
296+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
297+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
298+│ └──────────────────────────────────────────┘ │
299+└──────────────────────────────────────────────┘
300+'
301+OB_ON_NODE3='
302+┌──────────────────────────────────────────────┐
303+│ ┌──────────────────────────────────────────┐ │
304+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
305+│ │ │○ ││○ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
306+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
307+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
308+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
309+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
310+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
311+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
312+│ └──────────────────────────────────────────┘ │
313+└──────────────────────────────────────────────┘
314+'
315+OB_ON_NODE4='
316+┌──────────────────────────────────────────────┐
317+│ ┌──────────────────────────────────────────┐ │
318+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
319+│ │ │○ ││○ ││○ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
320+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
321+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
322+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
323+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
324+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
325+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
326+│ └──────────────────────────────────────────┘ │
327+└──────────────────────────────────────────────┘
328+'
329+OB_ON_NODE5='
330+┌──────────────────────────────────────────────┐
331+│ ┌──────────────────────────────────────────┐ │
332+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
333+│ │ │○ ││○ ││○ ││○ ││◉ ││○ ││○ ││○ ││○ ││○ │ │ │
334+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
335+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
336+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
337+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
338+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
339+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
340+│ └──────────────────────────────────────────┘ │
341+└──────────────────────────────────────────────┘
342+'
343+OB_ON_NODE6='
344+┌──────────────────────────────────────────────┐
345+│ ┌──────────────────────────────────────────┐ │
346+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
347+│ │ │○ ││○ ││○ ││○ ││○ ││◉ ││○ ││○ ││○ ││○ │ │ │
348+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
349+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
350+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
351+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
352+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
353+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
354+│ └──────────────────────────────────────────┘ │
355+└──────────────────────────────────────────────┘
356+'
357+OB_ON_NODE7='
358+┌──────────────────────────────────────────────┐
359+│ ┌──────────────────────────────────────────┐ │
360+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
361+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││◉ ││○ ││○ ││○ │ │ │
362+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
363+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
364+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
365+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
366+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
367+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
368+│ └──────────────────────────────────────────┘ │
369+└──────────────────────────────────────────────┘
370+'
371+OB_ON_NODE8='
372+┌──────────────────────────────────────────────┐
373+│ ┌──────────────────────────────────────────┐ │
374+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
375+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││◉ ││○ ││○ │ │ │
376+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
377+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
378+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
379+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
380+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
381+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
382+│ └──────────────────────────────────────────┘ │
383+└──────────────────────────────────────────────┘
384+'
385+OB_ON_NODE9='
386+┌──────────────────────────────────────────────┐
387+│ ┌──────────────────────────────────────────┐ │
388+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
389+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││◉ ││○ │ │ │
390+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
391+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
392+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
393+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
394+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
395+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
396+│ └──────────────────────────────────────────┘ │
397+└──────────────────────────────────────────────┘
398+'
399+OB_ON_NODE10='
400+┌──────────────────────────────────────────────┐
401+│ ┌──────────────────────────────────────────┐ │
402+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
403+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││◉ │ │ │
404+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
405+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
406+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
407+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
408+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
409+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
410+│ └──────────────────────────────────────────┘ │
411+└──────────────────────────────────────────────┘
412+'
413+OB_START_NODE1_2='
414+┌──────────────────────────────────────────────┐
415+│ ┌──────────────────────────────────────────┐ │
416+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
417+│ │ │◉ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
418+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
419+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
420+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
421+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
422+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
423+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
424+│ └──────────────────────────────────────────┘ │
425+└──────────────────────────────────────────────┘
426+'
427+OB_START_NODE1_3='
428+┌──────────────────────────────────────────────┐
429+│ ┌──────────────────────────────────────────┐ │
430+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
431+│ │ │◉ ││◉ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
432+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
433+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
434+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
435+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
436+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
437+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
438+│ └──────────────────────────────────────────┘ │
439+└──────────────────────────────────────────────┘
440+'
441+OB_START_NODE1_4='
442+┌──────────────────────────────────────────────┐
443+│ ┌──────────────────────────────────────────┐ │
444+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
445+│ │ │◉ ││◉ ││◉ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
446+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
447+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
448+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
449+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
450+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
451+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
452+│ └──────────────────────────────────────────┘ │
453+└──────────────────────────────────────────────┘
454+'
455+OB_START_NODE1_5='
456+┌──────────────────────────────────────────────┐
457+│ ┌──────────────────────────────────────────┐ │
458+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
459+│ │ │◉ ││◉ ││◉ ││◉ ││◎ ││○ ││○ ││○ ││○ ││○ │ │ │
460+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
461+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
462+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
463+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
464+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
465+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
466+│ └──────────────────────────────────────────┘ │
467+└──────────────────────────────────────────────┘
468+'
469+OB_START_NODE1_6='
470+┌──────────────────────────────────────────────┐
471+│ ┌──────────────────────────────────────────┐ │
472+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
473+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◎ ││○ ││○ ││○ ││○ │ │ │
474+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
475+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
476+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
477+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
478+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
479+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
480+│ └──────────────────────────────────────────┘ │
481+└──────────────────────────────────────────────┘
482+'
483+OB_START_NODE1_7='
484+┌──────────────────────────────────────────────┐
485+│ ┌──────────────────────────────────────────┐ │
486+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
487+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◎ ││○ ││○ ││○ │ │ │
488+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
489+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
490+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
491+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
492+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
493+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
494+│ └──────────────────────────────────────────┘ │
495+└──────────────────────────────────────────────┘
496+'
497+OB_START_NODE1_8='
498+┌──────────────────────────────────────────────┐
499+│ ┌──────────────────────────────────────────┐ │
500+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
501+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◎ ││○ ││○ │ │ │
502+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
503+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
504+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
505+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
506+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
507+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
508+│ └──────────────────────────────────────────┘ │
509+└──────────────────────────────────────────────┘
510+'◎
511+OB_START_NODE1_9='
512+┌──────────────────────────────────────────────┐
513+│ ┌──────────────────────────────────────────┐ │
514+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
515+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◎ ││○ │ │ │
516+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
517+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
518+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
519+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
520+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
521+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
522+│ └──────────────────────────────────────────┘ │
523+└──────────────────────────────────────────────┘
524+'
525+OB_START_NODE1_10='
526+┌──────────────────────────────────────────────┐
527+│ ┌──────────────────────────────────────────┐ │
528+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
529+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◎ │ │ │
530+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
531+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
532+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
533+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
534+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
535+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
536+│ └──────────────────────────────────────────┘ │
537+└──────────────────────────────────────────────┘
538+'
539+OB_ON_NODE1_2='
540+┌──────────────────────────────────────────────┐
541+│ ┌──────────────────────────────────────────┐ │
542+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
543+│ │ │◉ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
544+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
545+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
546+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
547+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
548+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
549+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
550+│ └──────────────────────────────────────────┘ │
551+└──────────────────────────────────────────────┘
552+'
553+OB_ON_NODE1_3='
554+┌──────────────────────────────────────────────┐
555+│ ┌──────────────────────────────────────────┐ │
556+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
557+│ │ │◉ ││◉ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
558+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
559+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
560+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
561+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
562+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
563+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
564+│ └──────────────────────────────────────────┘ │
565+└──────────────────────────────────────────────┘
566+'
567+OB_ON_NODE1_4='
568+┌──────────────────────────────────────────────┐
569+│ ┌──────────────────────────────────────────┐ │
570+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
571+│ │ │◉ ││◉ ││◉ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
572+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
573+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
574+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
575+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
576+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
577+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
578+│ └──────────────────────────────────────────┘ │
579+└──────────────────────────────────────────────┘
580+'
581+OB_ON_NODE1_5='
582+┌──────────────────────────────────────────────┐
583+│ ┌──────────────────────────────────────────┐ │
584+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
585+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││○ ││○ ││○ ││○ ││○ │ │ │
586+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
587+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
588+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
589+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
590+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
591+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
592+│ └──────────────────────────────────────────┘ │
593+└──────────────────────────────────────────────┘
594+'
595+OB_ON_NODE1_6='
596+┌──────────────────────────────────────────────┐
597+│ ┌──────────────────────────────────────────┐ │
598+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
599+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││○ ││○ ││○ ││○ │ │ │
600+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
601+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
602+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
603+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
604+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
605+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
606+│ └──────────────────────────────────────────┘ │
607+└──────────────────────────────────────────────┘
608+'
609+OB_ON_NODE1_7='
610+┌──────────────────────────────────────────────┐
611+│ ┌──────────────────────────────────────────┐ │
612+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
613+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││○ ││○ ││○ │ │ │
614+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
615+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
616+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
617+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
618+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
619+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
620+│ └──────────────────────────────────────────┘ │
621+└──────────────────────────────────────────────┘
622+'
623+OB_ON_NODE1_8='
624+┌──────────────────────────────────────────────┐
625+│ ┌──────────────────────────────────────────┐ │
626+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
627+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││○ ││○ │ │ │
628+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
629+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
630+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
631+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
632+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
633+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
634+│ └──────────────────────────────────────────┘ │
635+└──────────────────────────────────────────────┘
636+'
637+OB_ON_NODE1_9='
638+┌──────────────────────────────────────────────┐
639+│ ┌──────────────────────────────────────────┐ │
640+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
641+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││○ │ │ │
642+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
643+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
644+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
645+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
646+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
647+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
648+│ └──────────────────────────────────────────┘ │
649+└──────────────────────────────────────────────┘
650+'
651+
652+OB_ON_ALL='
653+┌──────────────────────────────────────────────┐
654+│ ┌──────────────────────────────────────────┐ │
655+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
656+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ │ │ │
657+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
658+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
659+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
660+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
661+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
662+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
663+│ └──────────────────────────────────────────┘ │
664+└──────────────────────────────────────────────┘
665+'
666+ShowLights() {
667+clear;printf "${OB_OFF}";sleep .5;clear;printf "${OB_START_ALL}";sleep .5
668+for i in {1..10};do clear;eval printf \"\$OB_START_NODE${i}\";sleep .25;clear;eval printf \"\$OB_ON_NODE${i}\"; sleep .25; done
669+for i in {10..1};do clear;eval printf \"\$OB_ON_NODE${i}\";sleep .25;clear;eval printf \"\$OB_START_NODE${i}\";sleep .25;done
670+clear;printf "${OB_ON_NODE1}";sleep .25
671+for i in {2..9};do clear; eval printf \"\$OB_START_NODE1_${i}\";sleep .25;clear;eval printf \"\$OB_ON_NODE1_${i}\"; sleep .25; done
672+clear;printf "${OB_START_NODE1_10}";sleep .25;clear;printf "${OB_ON_ALL}";sleep .15;clear;printf "${OB_START_NODE1_10}";sleep .25;
673+for i in {9..2};do clear; eval printf \"\$OB_START_NODE1_${i}\";sleep .25;clear;eval printf \"\$OB_ON_NODE1_${i}\"; sleep .25; done
674+clear;printf "${OB_ON_ALL}";sleep .5;clear;printf "${OB_START_ALL}";sleep .15;clear;printf "${OB_OFF}"
675+clear;printf "${OB_START_ALL}";sleep .5;clear;printf "${OB_OFF}";sleep .15
676+clear;printf "${OB_START_ALL}";sleep .5;clear;printf "${OB_OFF}";sleep .15
677+clear;printf "${OB_START_ALL}";clear;printf "${OB_OFF}";sleep .15
678+sleep 2
679+}
680
681=== added file 'etc/colors.b64'
682--- etc/colors.b64 1970-01-01 00:00:00 +0000
683+++ etc/colors.b64 2016-06-29 14:56:15 +0000
684@@ -0,0 +1,98 @@
685+MCxCTEFDSywjMDAwMDAwCjEsTUFST09OLCM4MDAwMDAKMixHUkVFTiwjMDA4MDAwCjMsT0xJVkUs
686+IzgwODAwMAo0LE5BVlksIzAwMDA4MAo1LFBVUlBMRSwjODAwMDgwCjYsVEVBTCwjMDA4MDgwCjcs
687+U0lMVkVSLCNjMGMwYzAKOCxHUkVZLCM4MDgwODAKOSxSRUQsI2ZmMDAwMAoxMCxMSU1FLCMwMGZm
688+MDAKMTEsWUVMTE9XLCNmZmZmMDAKMTIsQkxVRSwjMDAwMGZmCjEzLEZVQ0hTSUEsI2ZmMDBmZgox
689+NCxBUVVBLCMwMGZmZmYKMTUsV0hJVEUsI2ZmZmZmZgoxNixHUkVZMCwjMDAwMDAwCjE3LE5BVllC
690+TFVFLCMwMDAwNWYKMTgsREFSS0JMVUUsIzAwMDA4NwoxOSxCTFVFMywjMDAwMGFmCjIwLEJMVUUz
691+LCMwMDAwZDcKMjEsQkxVRTEsIzAwMDBmZgoyMixEQVJLR1JFRU4sIzAwNWYwMAoyMyxERUVQU0tZ
692+QkxVRTQsIzAwNWY1ZgoyNCxERUVQU0tZQkxVRTQsIzAwNWY4NwoyNSxERUVQU0tZQkxVRTQsIzAw
693+NWZhZgoyNixET0RHRVJCTFVFMywjMDA1ZmQ3CjI3LERPREdFUkJMVUUyLCMwMDVmZmYKMjgsR1JF
694+RU40LCMwMDg3MDAKMjksU1BSSU5HR1JFRU40LCMwMDg3NWYKMzAsVFVSUVVPSVNFNCwjMDA4Nzg3
695+CjMxLERFRVBTS1lCTFVFMywjMDA4N2FmCjMyLERFRVBTS1lCTFVFMywjMDA4N2Q3CjMzLERPREdF
696+UkJMVUUxLCMwMDg3ZmYKMzQsR1JFRU4zLCMwMGFmMDAKMzUsU1BSSU5HR1JFRU4zLCMwMGFmNWYK
697+MzYsREFSS0NZQU4sIzAwYWY4NwozNyxMSUdIVFNFQUdSRUVOLCMwMGFmYWYKMzgsREVFUFNLWUJM
698+VUUyLCMwMGFmZDcKMzksREVFUFNLWUJMVUUxLCMwMGFmZmYKNDAsR1JFRU4zLCMwMGQ3MDAKNDEs
699+U1BSSU5HR1JFRU4zLCMwMGQ3NWYKNDIsU1BSSU5HR1JFRU4yLCMwMGQ3ODcKNDMsQ1lBTjMsIzAw
700+ZDdhZgo0NCxEQVJLVFVSUVVPSVNFLCMwMGQ3ZDcKNDUsVFVSUVVPSVNFMiwjMDBkN2ZmCjQ2LEdS
701+RUVOMSwjMDBmZjAwCjQ3LFNQUklOR0dSRUVOMiwjMDBmZjVmCjQ4LFNQUklOR0dSRUVOMSwjMDBm
702+Zjg3CjQ5LE1FRElVTVNQUklOR0dSRUVOLCMwMGZmYWYKNTAsQ1lBTjIsIzAwZmZkNwo1MSxDWUFO
703+MSwjMDBmZmZmCjUyLERBUktSRUQsIzVmMDAwMAo1MyxERUVQUElOSzQsIzVmMDA1Zgo1NCxQVVJQ
704+TEU0LCM1ZjAwODcKNTUsUFVSUExFNCwjNWYwMGFmCjU2LFBVUlBMRTMsIzVmMDBkNwo1NyxCTFVF
705+VklPTEVULCM1ZjAwZmYKNTgsT1JBTkdFNCwjNWY1ZjAwCjU5LEdSRVkzNywjNWY1ZjVmCjYwLE1F
706+RElVTVBVUlBMRTQsIzVmNWY4Nwo2MSxTTEFURUJMVUUzLCM1ZjVmYWYKNjIsU0xBVEVCTFVFMywj
707+NWY1ZmQ3CjYzLFJPWUFMQkxVRTEsIzVmNWZmZgo2NCxDSEFSVFJFVVNFNCwjNWY4NzAwCjY1LERB
708+UktTRUFHUkVFTjQsIzVmODc1Zgo2NixQQUxFVFVSUVVPSVNFNCwjNWY4Nzg3CjY3LFNURUVMQkxV
709+RSwjNWY4N2FmCjY4LFNURUVMQkxVRTMsIzVmODdkNwo2OSxDT1JORkxPV0VSQkxVRSwjNWY4N2Zm
710+CjcwLENIQVJUUkVVU0UzLCM1ZmFmMDAKNzEsREFSS1NFQUdSRUVONCwjNWZhZjVmCjcyLENBREVU
711+QkxVRSwjNWZhZjg3CjczLENBREVUQkxVRSwjNWZhZmFmCjc0LFNLWUJMVUUzLCM1ZmFmZDcKNzUs
712+U1RFRUxCTFVFMSwjNWZhZmZmCjc2LENIQVJUUkVVU0UzLCM1ZmQ3MDAKNzcsUEFMRUdSRUVOMywj
713+NWZkNzVmCjc4LFNFQUdSRUVOMywjNWZkNzg3Cjc5LEFRVUFNQVJJTkUzLCM1ZmQ3YWYKODAsTUVE
714+SVVNVFVSUVVPSVNFLCM1ZmQ3ZDcKODEsU1RFRUxCTFVFMSwjNWZkN2ZmCjgyLENIQVJUUkVVU0Uy
715+LCM1ZmZmMDAKODMsU0VBR1JFRU4yLCM1ZmZmNWYKODQsU0VBR1JFRU4xLCM1ZmZmODcKODUsU0VB
716+R1JFRU4xLCM1ZmZmYWYKODYsQVFVQU1BUklORTEsIzVmZmZkNwo4NyxEQVJLU0xBVEVHUkFZMiwj
717+NWZmZmZmCjg4LERBUktSRUQsIzg3MDAwMAo4OSxERUVQUElOSzQsIzg3MDA1Zgo5MCxEQVJLTUFH
718+RU5UQSwjODcwMDg3CjkxLERBUktNQUdFTlRBLCM4NzAwYWYKOTIsREFSS1ZJT0xFVCwjODcwMGQ3
719+CjkzLFBVUlBMRSwjODcwMGZmCjk0LE9SQU5HRTQsIzg3NWYwMAo5NSxMSUdIVFBJTks0LCM4NzVm
720+NWYKOTYsUExVTTQsIzg3NWY4Nwo5NyxNRURJVU1QVVJQTEUzLCM4NzVmYWYKOTgsTUVESVVNUFVS
721+UExFMywjODc1ZmQ3Cjk5LFNMQVRFQkxVRTEsIzg3NWZmZgoxMDAsWUVMTE9XNCwjODc4NzAwCjEw
722+MSxXSEVBVDQsIzg3ODc1ZgoxMDIsR1JFWTUzLCM4Nzg3ODcKMTAzLExJR0hUU0xBVEVHUkVZLCM4
723+Nzg3YWYKMTA0LE1FRElVTVBVUlBMRSwjODc4N2Q3CjEwNSxMSUdIVFNMQVRFQkxVRSwjODc4N2Zm
724+CjEwNixZRUxMT1c0LCM4N2FmMDAKMTA3LERBUktPTElWRUdSRUVOMywjODdhZjVmCjEwOCxEQVJL
725+U0VBR1JFRU4sIzg3YWY4NwoxMDksTElHSFRTS1lCTFVFMywjODdhZmFmCjExMCxMSUdIVFNLWUJM
726+VUUzLCM4N2FmZDcKMTExLFNLWUJMVUUyLCM4N2FmZmYKMTEyLENIQVJUUkVVU0UyLCM4N2Q3MDAK
727+MTEzLERBUktPTElWRUdSRUVOMywjODdkNzVmCjExNCxQQUxFR1JFRU4zLCM4N2Q3ODcKMTE1LERB
728+UktTRUFHUkVFTjMsIzg3ZDdhZgoxMTYsREFSS1NMQVRFR1JBWTMsIzg3ZDdkNwoxMTcsU0tZQkxV
729+RTEsIzg3ZDdmZgoxMTgsQ0hBUlRSRVVTRTEsIzg3ZmYwMAoxMTksTElHSFRHUkVFTiwjODdmZjVm
730+CjEyMCxMSUdIVEdSRUVOLCM4N2ZmODcKMTIxLFBBTEVHUkVFTjEsIzg3ZmZhZgoxMjIsQVFVQU1B
731+UklORTEsIzg3ZmZkNwoxMjMsREFSS1NMQVRFR1JBWTEsIzg3ZmZmZgoxMjQsUkVEMywjYWYwMDAw
732+CjEyNSxERUVQUElOSzQsI2FmMDA1ZgoxMjYsTUVESVVNVklPTEVUUkVELCNhZjAwODcKMTI3LE1B
733+R0VOVEEzLCNhZjAwYWYKMTI4LERBUktWSU9MRVQsI2FmMDBkNwoxMjksUFVSUExFLCNhZjAwZmYK
734+MTMwLERBUktPUkFOR0UzLCNhZjVmMDAKMTMxLElORElBTlJFRCwjYWY1ZjVmCjEzMixIT1RQSU5L
735+MywjYWY1Zjg3CjEzMyxNRURJVU1PUkNISUQzLCNhZjVmYWYKMTM0LE1FRElVTU9SQ0hJRCwjYWY1
736+ZmQ3CjEzNSxNRURJVU1QVVJQTEUyLCNhZjVmZmYKMTM2LERBUktHT0xERU5ST0QsI2FmODcwMAox
737+MzcsTElHSFRTQUxNT04zLCNhZjg3NWYKMTM4LFJPU1lCUk9XTiwjYWY4Nzg3CjEzOSxHUkVZNjMs
738+I2FmODdhZgoxNDAsTUVESVVNUFVSUExFMiwjYWY4N2Q3CjE0MSxNRURJVU1QVVJQTEUxLCNhZjg3
739+ZmYKMTQyLEdPTEQzLCNhZmFmMDAKMTQzLERBUktLSEFLSSwjYWZhZjVmCjE0NCxOQVZBSk9XSElU
740+RTMsI2FmYWY4NwoxNDUsR1JFWTY5LCNhZmFmYWYKMTQ2LExJR0hUU1RFRUxCTFVFMywjYWZhZmQ3
741+CjE0NyxMSUdIVFNURUVMQkxVRSwjYWZhZmZmCjE0OCxZRUxMT1czLCNhZmQ3MDAKMTQ5LERBUktP
742+TElWRUdSRUVOMywjYWZkNzVmCjE1MCxEQVJLU0VBR1JFRU4zLCNhZmQ3ODcKMTUxLERBUktTRUFH
743+UkVFTjIsI2FmZDdhZgoxNTIsTElHSFRDWUFOMywjYWZkN2Q3CjE1MyxMSUdIVFNLWUJMVUUxLCNh
744+ZmQ3ZmYKMTU0LEdSRUVOWUVMTE9XLCNhZmZmMDAKMTU1LERBUktPTElWRUdSRUVOMiwjYWZmZjVm
745+CjE1NixQQUxFR1JFRU4xLCNhZmZmODcKMTU3LERBUktTRUFHUkVFTjIsI2FmZmZhZgoxNTgsREFS
746+S1NFQUdSRUVOMSwjYWZmZmQ3CjE1OSxQQUxFVFVSUVVPSVNFMSwjYWZmZmZmCjE2MCxSRUQzLCNk
747+NzAwMDAKMTYxLERFRVBQSU5LMywjZDcwMDVmCjE2MixERUVQUElOSzMsI2Q3MDA4NwoxNjMsTUFH
748+RU5UQTMsI2Q3MDBhZgoxNjQsTUFHRU5UQTMsI2Q3MDBkNwoxNjUsTUFHRU5UQTIsI2Q3MDBmZgox
749+NjYsREFSS09SQU5HRTMsI2Q3NWYwMAoxNjcsSU5ESUFOUkVELCNkNzVmNWYKMTY4LEhPVFBJTksz
750+LCNkNzVmODcKMTY5LEhPVFBJTksyLCNkNzVmYWYKMTcwLE9SQ0hJRCwjZDc1ZmQ3CjE3MSxNRURJ
751+VU1PUkNISUQxLCNkNzVmZmYKMTcyLE9SQU5HRTMsI2Q3ODcwMAoxNzMsTElHSFRTQUxNT04zLCNk
752+Nzg3NWYKMTc0LExJR0hUUElOSzMsI2Q3ODc4NwoxNzUsUElOSzMsI2Q3ODdhZgoxNzYsUExVTTMs
753+I2Q3ODdkNwoxNzcsVklPTEVULCNkNzg3ZmYKMTc4LEdPTEQzLCNkN2FmMDAKMTc5LExJR0hUR09M
754+REVOUk9EMywjZDdhZjVmCjE4MCxUQU4sI2Q3YWY4NwoxODEsTUlTVFlST1NFMywjZDdhZmFmCjE4
755+MixUSElTVExFMywjZDdhZmQ3CjE4MyxQTFVNMiwjZDdhZmZmCjE4NCxZRUxMT1czLCNkN2Q3MDAK
756+MTg1LEtIQUtJMywjZDdkNzVmCjE4NixMSUdIVEdPTERFTlJPRDIsI2Q3ZDc4NwoxODcsTElHSFRZ
757+RUxMT1czLCNkN2Q3YWYKMTg4LEdSRVk4NCwjZDdkN2Q3CjE4OSxMSUdIVFNURUVMQkxVRTEsI2Q3
758+ZDdmZgoxOTAsWUVMTE9XMiwjZDdmZjAwCjE5MSxEQVJLT0xJVkVHUkVFTjEsI2Q3ZmY1ZgoxOTIs
759+REFSS09MSVZFR1JFRU4xLCNkN2ZmODcKMTkzLERBUktTRUFHUkVFTjEsI2Q3ZmZhZgoxOTQsSE9O
760+RVlERVcyLCNkN2ZmZDcKMTk1LExJR0hUQ1lBTjEsI2Q3ZmZmZgoxOTYsUkVEMSwjZmYwMDAwCjE5
761+NyxERUVQUElOSzIsI2ZmMDA1ZgoxOTgsREVFUFBJTksxLCNmZjAwODcKMTk5LERFRVBQSU5LMSwj
762+ZmYwMGFmCjIwMCxNQUdFTlRBMiwjZmYwMGQ3CjIwMSxNQUdFTlRBMSwjZmYwMGZmCjIwMixPUkFO
763+R0VSRUQxLCNmZjVmMDAKMjAzLElORElBTlJFRDEsI2ZmNWY1ZgoyMDQsSU5ESUFOUkVEMSwjZmY1
764+Zjg3CjIwNSxIT1RQSU5LLCNmZjVmYWYKMjA2LEhPVFBJTkssI2ZmNWZkNwoyMDcsTUVESVVNT1JD
765+SElEMSwjZmY1ZmZmCjIwOCxEQVJLT1JBTkdFLCNmZjg3MDAKMjA5LFNBTE1PTjEsI2ZmODc1Zgoy
766+MTAsTElHSFRDT1JBTCwjZmY4Nzg3CjIxMSxQQUxFVklPTEVUUkVEMSwjZmY4N2FmCjIxMixPUkNI
767+SUQyLCNmZjg3ZDcKMjEzLE9SQ0hJRDEsI2ZmODdmZgoyMTQsT1JBTkdFMSwjZmZhZjAwCjIxNSxT
768+QU5EWUJST1dOLCNmZmFmNWYKMjE2LExJR0hUU0FMTU9OMSwjZmZhZjg3CjIxNyxMSUdIVFBJTksx
769+LCNmZmFmYWYKMjE4LFBJTksxLCNmZmFmZDcKMjE5LFBMVU0xLCNmZmFmZmYKMjIwLEdPTEQxLCNm
770+ZmQ3MDAKMjIxLExJR0hUR09MREVOUk9EMiwjZmZkNzVmCjIyMixMSUdIVEdPTERFTlJPRDIsI2Zm
771+ZDc4NwoyMjMsTkFWQUpPV0hJVEUxLCNmZmQ3YWYKMjI0LE1JU1RZUk9TRTEsI2ZmZDdkNwoyMjUs
772+VEhJU1RMRTEsI2ZmZDdmZgoyMjYsWUVMTE9XMSwjZmZmZjAwCjIyNyxMSUdIVEdPTERFTlJPRDEs
773+I2ZmZmY1ZgoyMjgsS0hBS0kxLCNmZmZmODcKMjI5LFdIRUFUMSwjZmZmZmFmCjIzMCxDT1JOU0lM
774+SzEsI2ZmZmZkNwoyMzEsR1JFWTEwMCwjZmZmZmZmCjIzMixHUkVZMywjMDgwODA4CjIzMyxHUkVZ
775+NywjMTIxMjEyCjIzNCxHUkVZMTEsIzFjMWMxYwoyMzUsR1JFWTE1LCMyNjI2MjYKMjM2LEdSRVkx
776+OSwjMzAzMDMwCjIzNyxHUkVZMjMsIzNhM2EzYQoyMzgsR1JFWTI3LCM0NDQ0NDQKMjM5LEdSRVkz
777+MCwjNGU0ZTRlCjI0MCxHUkVZMzUsIzU4NTg1OAoyNDEsR1JFWTM5LCM2MjYyNjIKMjQyLEdSRVk0
778+MiwjNmM2YzZjCjI0MyxHUkVZNDYsIzc2NzY3NgoyNDQsR1JFWTUwLCM4MDgwODAKMjQ1LEdSRVk1
779+NCwjOGE4YThhCjI0NixHUkVZNTgsIzk0OTQ5NAoyNDcsR1JFWTYyLCM5ZTllOWUKMjQ4LEdSRVk2
780+NiwjYThhOGE4CjI0OSxHUkVZNzAsI2IyYjJiMgoyNTAsR1JFWTc0LCNiY2JjYmMKMjUxLEdSRVk3
781+OCwjYzZjNmM2CjI1MixHUkVZODIsI2QwZDBkMAoyNTMsR1JFWTg1LCNkYWRhZGEKMjU0LEdSRVk4
782+OSwjZTRlNGU0CjI1NSxHUkVZOTMsI2VlZWVlZQo=
783
784=== added file 'functions'
785--- functions 1970-01-01 00:00:00 +0000
786+++ functions 2016-06-29 14:56:15 +0000
787@@ -0,0 +1,2313 @@
788+##############################################################################
789+# functions - A centralized functions file for Canonical Solution Architects
790+# to source in their scripts
791+#
792+#
793+# Author(s): Craig Bender
794+#
795+# This program is free software: you can redistribute it and/or modify
796+# it under the terms of the GNU General Public License as published by
797+# the Free Software Foundation, version 3 of the License.
798+#
799+# This program is distributed in the hope that it will be useful,
800+# but WITHOUT ANY WARRANTY; without even the implied warranty of
801+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
802+# GNU General Public License for more details.
803+#
804+# You should have received a copy of the GNU General Public License
805+# along with this program. If not, see <http://www.gnu.org/licenses/>.
806+#
807+# Copyright (C) 2014 Canonical Ltd.
808+#
809+##############################################################################
810+
811+#Ensure that this script is being source, rather than being executed
812+RSCHK=$_
813+[[ $RSCHK != $0 ]] || { echo "Error: ${SOURCEDIR}/${BASH_SOURCE[@]##*/} is being ran directly! Please \"source\" this script."; exit; }
814+
815+#Get full path and name of this script, regardless of where it is sourced from
816+SOURCEDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
817+export FUNCTIONS_FILE="${SOURCEDIR}/${BASH_SOURCE[@]##*/}"
818+
819+#Setup a general log for function related errors
820+[[ $EUID -eq 0 ]] && export FUNCLOG="/var/log/cpe-sa.functions.err.log" || export FUNCLOG="$HOME/cpe-sa.functions.err.log"
821+[[ ! -f $FUNCLOG ]] && touch $FUNCLOG
822+# Set standard IFS to space, tab and CR
823+IFS=$' \t\n'
824+
825+# Set True/False to Uppercase for easier logic tests
826+export TRUE=true
827+export FALSE=false
828+
829+#Create Timestamp variable.
830+#NOTE: Run/exec $TStamp rather using as a variable so it will be up to date
831+export TStamp=$(echo date +%Y-%m-%d-%H_%M_%S)
832+
833+#Make sure we can work with hidden files, if need be
834+shopt -s dotglob
835+
836+########################################
837+# Text Functions
838+########################################
839+#ColorsBase64 is a text file correlates xterm colors to names and hex approximates
840+ColorsBase64='
841+MCxCTEFDSywjMDAwMDAwCjEsTUFST09OLCM4MDAwMDAKMixHUkVFTiwjMDA4MDAwCjMsT0xJVkUs
842+IzgwODAwMAo0LE5BVlksIzAwMDA4MAo1LFBVUlBMRSwjODAwMDgwCjYsVEVBTCwjMDA4MDgwCjcs
843+U0lMVkVSLCNjMGMwYzAKOCxHUkVZLCM4MDgwODAKOSxSRUQsI2ZmMDAwMAoxMCxMSU1FLCMwMGZm
844+MDAKMTEsWUVMTE9XLCNmZmZmMDAKMTIsQkxVRSwjMDAwMGZmCjEzLEZVQ0hTSUEsI2ZmMDBmZgox
845+NCxBUVVBLCMwMGZmZmYKMTUsV0hJVEUsI2ZmZmZmZgoxNixHUkVZMCwjMDAwMDAwCjE3LE5BVllC
846+TFVFLCMwMDAwNWYKMTgsREFSS0JMVUUsIzAwMDA4NwoxOSxCTFVFMywjMDAwMGFmCjIwLEJMVUUz
847+LCMwMDAwZDcKMjEsQkxVRTEsIzAwMDBmZgoyMixEQVJLR1JFRU4sIzAwNWYwMAoyMyxERUVQU0tZ
848+QkxVRTQsIzAwNWY1ZgoyNCxERUVQU0tZQkxVRTQsIzAwNWY4NwoyNSxERUVQU0tZQkxVRTQsIzAw
849+NWZhZgoyNixET0RHRVJCTFVFMywjMDA1ZmQ3CjI3LERPREdFUkJMVUUyLCMwMDVmZmYKMjgsR1JF
850+RU40LCMwMDg3MDAKMjksU1BSSU5HR1JFRU40LCMwMDg3NWYKMzAsVFVSUVVPSVNFNCwjMDA4Nzg3
851+CjMxLERFRVBTS1lCTFVFMywjMDA4N2FmCjMyLERFRVBTS1lCTFVFMywjMDA4N2Q3CjMzLERPREdF
852+UkJMVUUxLCMwMDg3ZmYKMzQsR1JFRU4zLCMwMGFmMDAKMzUsU1BSSU5HR1JFRU4zLCMwMGFmNWYK
853+MzYsREFSS0NZQU4sIzAwYWY4NwozNyxMSUdIVFNFQUdSRUVOLCMwMGFmYWYKMzgsREVFUFNLWUJM
854+VUUyLCMwMGFmZDcKMzksREVFUFNLWUJMVUUxLCMwMGFmZmYKNDAsR1JFRU4zLCMwMGQ3MDAKNDEs
855+U1BSSU5HR1JFRU4zLCMwMGQ3NWYKNDIsU1BSSU5HR1JFRU4yLCMwMGQ3ODcKNDMsQ1lBTjMsIzAw
856+ZDdhZgo0NCxEQVJLVFVSUVVPSVNFLCMwMGQ3ZDcKNDUsVFVSUVVPSVNFMiwjMDBkN2ZmCjQ2LEdS
857+RUVOMSwjMDBmZjAwCjQ3LFNQUklOR0dSRUVOMiwjMDBmZjVmCjQ4LFNQUklOR0dSRUVOMSwjMDBm
858+Zjg3CjQ5LE1FRElVTVNQUklOR0dSRUVOLCMwMGZmYWYKNTAsQ1lBTjIsIzAwZmZkNwo1MSxDWUFO
859+MSwjMDBmZmZmCjUyLERBUktSRUQsIzVmMDAwMAo1MyxERUVQUElOSzQsIzVmMDA1Zgo1NCxQVVJQ
860+TEU0LCM1ZjAwODcKNTUsUFVSUExFNCwjNWYwMGFmCjU2LFBVUlBMRTMsIzVmMDBkNwo1NyxCTFVF
861+VklPTEVULCM1ZjAwZmYKNTgsT1JBTkdFNCwjNWY1ZjAwCjU5LEdSRVkzNywjNWY1ZjVmCjYwLE1F
862+RElVTVBVUlBMRTQsIzVmNWY4Nwo2MSxTTEFURUJMVUUzLCM1ZjVmYWYKNjIsU0xBVEVCTFVFMywj
863+NWY1ZmQ3CjYzLFJPWUFMQkxVRTEsIzVmNWZmZgo2NCxDSEFSVFJFVVNFNCwjNWY4NzAwCjY1LERB
864+UktTRUFHUkVFTjQsIzVmODc1Zgo2NixQQUxFVFVSUVVPSVNFNCwjNWY4Nzg3CjY3LFNURUVMQkxV
865+RSwjNWY4N2FmCjY4LFNURUVMQkxVRTMsIzVmODdkNwo2OSxDT1JORkxPV0VSQkxVRSwjNWY4N2Zm
866+CjcwLENIQVJUUkVVU0UzLCM1ZmFmMDAKNzEsREFSS1NFQUdSRUVONCwjNWZhZjVmCjcyLENBREVU
867+QkxVRSwjNWZhZjg3CjczLENBREVUQkxVRSwjNWZhZmFmCjc0LFNLWUJMVUUzLCM1ZmFmZDcKNzUs
868+U1RFRUxCTFVFMSwjNWZhZmZmCjc2LENIQVJUUkVVU0UzLCM1ZmQ3MDAKNzcsUEFMRUdSRUVOMywj
869+NWZkNzVmCjc4LFNFQUdSRUVOMywjNWZkNzg3Cjc5LEFRVUFNQVJJTkUzLCM1ZmQ3YWYKODAsTUVE
870+SVVNVFVSUVVPSVNFLCM1ZmQ3ZDcKODEsU1RFRUxCTFVFMSwjNWZkN2ZmCjgyLENIQVJUUkVVU0Uy
871+LCM1ZmZmMDAKODMsU0VBR1JFRU4yLCM1ZmZmNWYKODQsU0VBR1JFRU4xLCM1ZmZmODcKODUsU0VB
872+R1JFRU4xLCM1ZmZmYWYKODYsQVFVQU1BUklORTEsIzVmZmZkNwo4NyxEQVJLU0xBVEVHUkFZMiwj
873+NWZmZmZmCjg4LERBUktSRUQsIzg3MDAwMAo4OSxERUVQUElOSzQsIzg3MDA1Zgo5MCxEQVJLTUFH
874+RU5UQSwjODcwMDg3CjkxLERBUktNQUdFTlRBLCM4NzAwYWYKOTIsREFSS1ZJT0xFVCwjODcwMGQ3
875+CjkzLFBVUlBMRSwjODcwMGZmCjk0LE9SQU5HRTQsIzg3NWYwMAo5NSxMSUdIVFBJTks0LCM4NzVm
876+NWYKOTYsUExVTTQsIzg3NWY4Nwo5NyxNRURJVU1QVVJQTEUzLCM4NzVmYWYKOTgsTUVESVVNUFVS
877+UExFMywjODc1ZmQ3Cjk5LFNMQVRFQkxVRTEsIzg3NWZmZgoxMDAsWUVMTE9XNCwjODc4NzAwCjEw
878+MSxXSEVBVDQsIzg3ODc1ZgoxMDIsR1JFWTUzLCM4Nzg3ODcKMTAzLExJR0hUU0xBVEVHUkVZLCM4
879+Nzg3YWYKMTA0LE1FRElVTVBVUlBMRSwjODc4N2Q3CjEwNSxMSUdIVFNMQVRFQkxVRSwjODc4N2Zm
880+CjEwNixZRUxMT1c0LCM4N2FmMDAKMTA3LERBUktPTElWRUdSRUVOMywjODdhZjVmCjEwOCxEQVJL
881+U0VBR1JFRU4sIzg3YWY4NwoxMDksTElHSFRTS1lCTFVFMywjODdhZmFmCjExMCxMSUdIVFNLWUJM
882+VUUzLCM4N2FmZDcKMTExLFNLWUJMVUUyLCM4N2FmZmYKMTEyLENIQVJUUkVVU0UyLCM4N2Q3MDAK
883+MTEzLERBUktPTElWRUdSRUVOMywjODdkNzVmCjExNCxQQUxFR1JFRU4zLCM4N2Q3ODcKMTE1LERB
884+UktTRUFHUkVFTjMsIzg3ZDdhZgoxMTYsREFSS1NMQVRFR1JBWTMsIzg3ZDdkNwoxMTcsU0tZQkxV
885+RTEsIzg3ZDdmZgoxMTgsQ0hBUlRSRVVTRTEsIzg3ZmYwMAoxMTksTElHSFRHUkVFTiwjODdmZjVm
886+CjEyMCxMSUdIVEdSRUVOLCM4N2ZmODcKMTIxLFBBTEVHUkVFTjEsIzg3ZmZhZgoxMjIsQVFVQU1B
887+UklORTEsIzg3ZmZkNwoxMjMsREFSS1NMQVRFR1JBWTEsIzg3ZmZmZgoxMjQsUkVEMywjYWYwMDAw
888+CjEyNSxERUVQUElOSzQsI2FmMDA1ZgoxMjYsTUVESVVNVklPTEVUUkVELCNhZjAwODcKMTI3LE1B
889+R0VOVEEzLCNhZjAwYWYKMTI4LERBUktWSU9MRVQsI2FmMDBkNwoxMjksUFVSUExFLCNhZjAwZmYK
890+MTMwLERBUktPUkFOR0UzLCNhZjVmMDAKMTMxLElORElBTlJFRCwjYWY1ZjVmCjEzMixIT1RQSU5L
891+MywjYWY1Zjg3CjEzMyxNRURJVU1PUkNISUQzLCNhZjVmYWYKMTM0LE1FRElVTU9SQ0hJRCwjYWY1
892+ZmQ3CjEzNSxNRURJVU1QVVJQTEUyLCNhZjVmZmYKMTM2LERBUktHT0xERU5ST0QsI2FmODcwMAox
893+MzcsTElHSFRTQUxNT04zLCNhZjg3NWYKMTM4LFJPU1lCUk9XTiwjYWY4Nzg3CjEzOSxHUkVZNjMs
894+I2FmODdhZgoxNDAsTUVESVVNUFVSUExFMiwjYWY4N2Q3CjE0MSxNRURJVU1QVVJQTEUxLCNhZjg3
895+ZmYKMTQyLEdPTEQzLCNhZmFmMDAKMTQzLERBUktLSEFLSSwjYWZhZjVmCjE0NCxOQVZBSk9XSElU
896+RTMsI2FmYWY4NwoxNDUsR1JFWTY5LCNhZmFmYWYKMTQ2LExJR0hUU1RFRUxCTFVFMywjYWZhZmQ3
897+CjE0NyxMSUdIVFNURUVMQkxVRSwjYWZhZmZmCjE0OCxZRUxMT1czLCNhZmQ3MDAKMTQ5LERBUktP
898+TElWRUdSRUVOMywjYWZkNzVmCjE1MCxEQVJLU0VBR1JFRU4zLCNhZmQ3ODcKMTUxLERBUktTRUFH
899+UkVFTjIsI2FmZDdhZgoxNTIsTElHSFRDWUFOMywjYWZkN2Q3CjE1MyxMSUdIVFNLWUJMVUUxLCNh
900+ZmQ3ZmYKMTU0LEdSRUVOWUVMTE9XLCNhZmZmMDAKMTU1LERBUktPTElWRUdSRUVOMiwjYWZmZjVm
901+CjE1NixQQUxFR1JFRU4xLCNhZmZmODcKMTU3LERBUktTRUFHUkVFTjIsI2FmZmZhZgoxNTgsREFS
902+S1NFQUdSRUVOMSwjYWZmZmQ3CjE1OSxQQUxFVFVSUVVPSVNFMSwjYWZmZmZmCjE2MCxSRUQzLCNk
903+NzAwMDAKMTYxLERFRVBQSU5LMywjZDcwMDVmCjE2MixERUVQUElOSzMsI2Q3MDA4NwoxNjMsTUFH
904+RU5UQTMsI2Q3MDBhZgoxNjQsTUFHRU5UQTMsI2Q3MDBkNwoxNjUsTUFHRU5UQTIsI2Q3MDBmZgox
905+NjYsREFSS09SQU5HRTMsI2Q3NWYwMAoxNjcsSU5ESUFOUkVELCNkNzVmNWYKMTY4LEhPVFBJTksz
906+LCNkNzVmODcKMTY5LEhPVFBJTksyLCNkNzVmYWYKMTcwLE9SQ0hJRCwjZDc1ZmQ3CjE3MSxNRURJ
907+VU1PUkNISUQxLCNkNzVmZmYKMTcyLE9SQU5HRTMsI2Q3ODcwMAoxNzMsTElHSFRTQUxNT04zLCNk
908+Nzg3NWYKMTc0LExJR0hUUElOSzMsI2Q3ODc4NwoxNzUsUElOSzMsI2Q3ODdhZgoxNzYsUExVTTMs
909+I2Q3ODdkNwoxNzcsVklPTEVULCNkNzg3ZmYKMTc4LEdPTEQzLCNkN2FmMDAKMTc5LExJR0hUR09M
910+REVOUk9EMywjZDdhZjVmCjE4MCxUQU4sI2Q3YWY4NwoxODEsTUlTVFlST1NFMywjZDdhZmFmCjE4
911+MixUSElTVExFMywjZDdhZmQ3CjE4MyxQTFVNMiwjZDdhZmZmCjE4NCxZRUxMT1czLCNkN2Q3MDAK
912+MTg1LEtIQUtJMywjZDdkNzVmCjE4NixMSUdIVEdPTERFTlJPRDIsI2Q3ZDc4NwoxODcsTElHSFRZ
913+RUxMT1czLCNkN2Q3YWYKMTg4LEdSRVk4NCwjZDdkN2Q3CjE4OSxMSUdIVFNURUVMQkxVRTEsI2Q3
914+ZDdmZgoxOTAsWUVMTE9XMiwjZDdmZjAwCjE5MSxEQVJLT0xJVkVHUkVFTjEsI2Q3ZmY1ZgoxOTIs
915+REFSS09MSVZFR1JFRU4xLCNkN2ZmODcKMTkzLERBUktTRUFHUkVFTjEsI2Q3ZmZhZgoxOTQsSE9O
916+RVlERVcyLCNkN2ZmZDcKMTk1LExJR0hUQ1lBTjEsI2Q3ZmZmZgoxOTYsUkVEMSwjZmYwMDAwCjE5
917+NyxERUVQUElOSzIsI2ZmMDA1ZgoxOTgsREVFUFBJTksxLCNmZjAwODcKMTk5LERFRVBQSU5LMSwj
918+ZmYwMGFmCjIwMCxNQUdFTlRBMiwjZmYwMGQ3CjIwMSxNQUdFTlRBMSwjZmYwMGZmCjIwMixPUkFO
919+R0VSRUQxLCNmZjVmMDAKMjAzLElORElBTlJFRDEsI2ZmNWY1ZgoyMDQsSU5ESUFOUkVEMSwjZmY1
920+Zjg3CjIwNSxIT1RQSU5LLCNmZjVmYWYKMjA2LEhPVFBJTkssI2ZmNWZkNwoyMDcsTUVESVVNT1JD
921+SElEMSwjZmY1ZmZmCjIwOCxEQVJLT1JBTkdFLCNmZjg3MDAKMjA5LFNBTE1PTjEsI2ZmODc1Zgoy
922+MTAsTElHSFRDT1JBTCwjZmY4Nzg3CjIxMSxQQUxFVklPTEVUUkVEMSwjZmY4N2FmCjIxMixPUkNI
923+SUQyLCNmZjg3ZDcKMjEzLE9SQ0hJRDEsI2ZmODdmZgoyMTQsT1JBTkdFMSwjZmZhZjAwCjIxNSxT
924+QU5EWUJST1dOLCNmZmFmNWYKMjE2LExJR0hUU0FMTU9OMSwjZmZhZjg3CjIxNyxMSUdIVFBJTksx
925+LCNmZmFmYWYKMjE4LFBJTksxLCNmZmFmZDcKMjE5LFBMVU0xLCNmZmFmZmYKMjIwLEdPTEQxLCNm
926+ZmQ3MDAKMjIxLExJR0hUR09MREVOUk9EMiwjZmZkNzVmCjIyMixMSUdIVEdPTERFTlJPRDIsI2Zm
927+ZDc4NwoyMjMsTkFWQUpPV0hJVEUxLCNmZmQ3YWYKMjI0LE1JU1RZUk9TRTEsI2ZmZDdkNwoyMjUs
928+VEhJU1RMRTEsI2ZmZDdmZgoyMjYsWUVMTE9XMSwjZmZmZjAwCjIyNyxMSUdIVEdPTERFTlJPRDEs
929+I2ZmZmY1ZgoyMjgsS0hBS0kxLCNmZmZmODcKMjI5LFdIRUFUMSwjZmZmZmFmCjIzMCxDT1JOU0lM
930+SzEsI2ZmZmZkNwoyMzEsR1JFWTEwMCwjZmZmZmZmCjIzMixHUkVZMywjMDgwODA4CjIzMyxHUkVZ
931+NywjMTIxMjEyCjIzNCxHUkVZMTEsIzFjMWMxYwoyMzUsR1JFWTE1LCMyNjI2MjYKMjM2LEdSRVkx
932+OSwjMzAzMDMwCjIzNyxHUkVZMjMsIzNhM2EzYQoyMzgsR1JFWTI3LCM0NDQ0NDQKMjM5LEdSRVkz
933+MCwjNGU0ZTRlCjI0MCxHUkVZMzUsIzU4NTg1OAoyNDEsR1JFWTM5LCM2MjYyNjIKMjQyLEdSRVk0
934+MiwjNmM2YzZjCjI0MyxHUkVZNDYsIzc2NzY3NgoyNDQsR1JFWTUwLCM4MDgwODAKMjQ1LEdSRVk1
935+NCwjOGE4YThhCjI0NixHUkVZNTgsIzk0OTQ5NAoyNDcsR1JFWTYyLCM5ZTllOWUKMjQ4LEdSRVk2
936+NiwjYThhOGE4CjI0OSxHUkVZNzAsI2IyYjJiMgoyNTAsR1JFWTc0LCNiY2JjYmMKMjUxLEdSRVk3
937+OCwjYzZjNmM2CjI1MixHUkVZODIsI2QwZDBkMAoyNTMsR1JFWTg1LCNkYWRhZGEKMjU0LEdSRVk4
938+OSwjZTRlNGU0CjI1NSxHUkVZOTMsI2VlZWVlZQo=
939+'
940+
941+GenColors() {
942+ echo -n "$ColorsBase64"|base64 -d > /tmp/xterm_colors.csv
943+ if [[ $? -eq 0 && -f /tmp/xterm_colors.csv ]];then
944+ local IFS=$'\n'
945+ for cVal in $(awk -F, '{printf "export R_"$2"='\''\\e[0m\\e[38;5;"$1"m'\''\nexport R_"$1"=$R_"$2"\n"}' /tmp/xterm_colors.csv);do
946+ eval export "${cVal}"
947+ done
948+ for cVal in $(awk -F, '{printf "export B_"$2"='\''\\e[0m\\e[1;38;5;"$1"m'\''\nexport B_"$1"=$R_"$2"\n"}' /tmp/xterm_colors.csv);do
949+ eval export "${cVal}"
950+ done
951+ for cVal in $(awk -F, '{printf "export BG_RW_"$2"='\''\\e[0m\\e[48;5;"$1"m'\''\nexport BG_RW_"$1"=$BG_RW_"$2"\n"}' /tmp/xterm_colors.csv);do
952+ eval export "${cVal}"
953+ done
954+ for cVal in $(awk -F, '{printf "export BG_BW_"$2"='\''\\e[0m\\e[1;48;5;"$1"m'\''\nexport BG_BW_"$1"=$BG_BW_"$2"\n"}' /tmp/xterm_colors.csv);do
955+ eval export "${cVal}"
956+ done
957+ for cVal in $(awk -F, '{printf "export BG_RB_"$2"='\''\\e[0m\\e[38;5;16;48;5;"$1"m'\''\nexport BG_RB_"$1"=$BG_RB_"$2"\n"}' /tmp/xterm_colors.csv);do
958+ eval export "${cVal}"
959+ done
960+ for cVal in $(awk -F, '{printf "export BG_BB_"$2"='\''\\e[0m\\e[1;38;5;16;48;5;"$1"m'\''\nexport BG_BB_"$1"=$BG_BB_"$2"\n"}' /tmp/xterm_colors.csv);do
961+ eval export "${cVal}"
962+ done
963+ for cVal in $(awk -F, '{printf "export REV_R_"$2"='\''\\e[0m\\e[38;5;"$1";48;5;255m'\''\nexport REV_R_"$1"=$REV_R_"$2"\n"}' /tmp/xterm_colors.csv);do
964+ eval export "${cVal}"
965+ done
966+ for cVal in $(awk -F, '{printf "export REV_B_"$2"='\''\\e[0m\\e[1;38;5;"$1";48;5;255m'\''\nexport REV_B_"$1"=$REV_B_"$2"\n"}' /tmp/xterm_colors.csv);do
967+ eval export "${cVal}"
968+ done
969+ else
970+ for i in {0..255};do
971+ eval "export R_"$i"='\e[0m\e[38;5;"$i"m'"
972+ eval "export B_"$i"='\e[0m\e[1;38;5;"$i"m'"
973+ eval "export BG_RW_"$i"='\e[0m\e[48;5;"$i"m'"
974+ eval "export BG_BW_"$i"='\e[0m\e[1;48;5;"$i"m'"
975+ eval "export BG_RB_"$i"='\e[0m\e[38;5;16;48;5;"$i"m'"
976+ eval "export BG_BB_"$i"='\e[0m\e[1;38;5;16;48;5;"$i"m'"
977+ eval "export REV_R_"$i"='\e[0m\e[38;5;"$i";48;5;255m'"
978+ eval "export REV_B_"$i"='\e[0m\e[1;38;5;"$i";48;5;255m'"
979+ done
980+ fi
981+}
982+
983+ShowColors_ByNum () {
984+printf '\n\n'${BU}'Foreground Regular Text'${RT}'\n\n';i=0;for i in {0..255}; do [[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[38;5;'${i}'m ${R_'${i}'}\t\e[0m';done;printf '\n'
985+printf '\n\n'${BU}'Foreground Bold Text'${RT}'\n\n';i=0;for i in {0..255}; do [[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[1;38;5;'${i}'m ${B_'${i}'}\t\e[0m';done;printf '\n'
986+printf '\n\n'${BU}'Background Fill Regular Text'${RT}'\n\n';i=0;for i in {0..255}; do [[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[48;5;'${i}'m ${BG_RW_'${i}'}\t\e[0m';done;printf '\n'
987+printf '\n\n'${BU}'nBackGround Fill Bold White Text'${RT}'\n\n';i=0;for i in {0..255}; do [[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[1;48;5;'${i}'m ${BG_BW_'${i}'}\t\e[0m';done;printf '\n'
988+printf '\n\n'${BU}'nBackground Fill Regular Black Text'${RT}'\n\n';i=0;for i in {0..255}; do [[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[38;5;16;48;5;'${i}'m ${BG_RB_'${i}'}\t\e[0m';done;printf '\n'
989+printf '\n\n'${BU}'Background Fill Bold Black Text'${RT}'\n\n';fi=0;for i in {0..255}; do [[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[1;38;5;16;48;5;'${i}'m ${BG_BB_'${i}'}\t\e[0m';done;printf '\n'
990+printf '\n\n'${BU}'Reverse Video Regular Text'${RT}'\n\n';i=0;for i in {0..255}; do [[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[38;5;'${i}';48;5;255m ${REV_R_'${i}'}\t\e[0m';done;printf '\n'
991+printf '\n\n'${BU}'Reverse Video Bold Text'${RT}'\n\n';i=0;for i in {0..255}; do [[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[1;38;5;'${i}';48;5;255m ${REV_B_'${i}'}\t\e[0m';done;printf '\n'
992+}
993+
994+ShowColors_ByName () {
995+for i in {0..255};do ColorName=$(awk -F, '/^'"${i}"',/{print $2}' /tmp/xterm_colors.csv);[[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[38;5;'${i}'m${R_'${ColorName}'}\e[0m';[[ ${#ColorName} -lt 10 ]] && printf '\t\t' || printf '\t';done;printf '\n'
996+for i in {0..255};do ColorName=$(awk -F, '/^'"${i}"',/{print $2}' /tmp/xterm_colors.csv);[[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[1;38;5;'${i}'m${B_'${ColorName}'}\e[0m';[[ ${#ColorName} -lt 10 ]] && printf '\t\t' || printf '\t';done;printf '\n'
997+for i in {0..255};do ColorName=$(awk -F, '/^'"${i}"',/{print $2}' /tmp/xterm_colors.csv);[[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[48;5;'${i}'m${BG_RW_'${ColorName}'}\e[0m';[[ ${#ColorName} -lt 10 ]] && printf '\t';done;printf '\n'
998+for i in {0..255};do ColorName=$(awk -F, '/^'"${i}"',/{print $2}' /tmp/xterm_colors.csv);[[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[1;48;5;'${i}'m${BG_BW_'${ColorName}'}\e[0m';[[ ${#ColorName} -lt 8 ]] && printf '\t';done;printf '\n'
999+for i in {0..255};do ColorName=$(awk -F, '/^'"${i}"',/{print $2}' /tmp/xterm_colors.csv);[[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[38;5;16;48;5;'${i}'m${BG_RB_'${ColorName}'}\e[0m';[[ ${#ColorName} -lt 8 ]] && printf '\t';done;printf '\n'
1000+for i in {0..255};do ColorName=$(awk -F, '/^'"${i}"',/{print $2}' /tmp/xterm_colors.csv);[[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[1;38;5;16;48;5;'${i}'m${BG_BB_'${ColorName}'}\e[0m';[[ ${#ColorName} -lt 8 ]] && printf '\t';done;printf '\n'
1001+for i in {0..255};do ColorName=$(awk -F, '/^'"${i}"',/{print $2}' /tmp/xterm_colors.csv);[[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[38;5;'${i}';48;5;255m${BG_R_'${ColorName}'}\e[0m';[[ ${#ColorName} -lt 8 ]] && printf '\t';done;printf '\n'
1002+for i in {0..255};do ColorName=$(awk -F, '/^'"${i}"',/{print $2}' /tmp/xterm_colors.csv);[[ $((${i} % 6)) -eq 0 ]] && printf '\n';printf '%-1s\e[0m\e[1;38;5;'${i}';48;5;255m${REV_B_'${ColorName}'}\e[0m';[[ ${#ColorName} -lt 8 ]] && printf '\t';done;printf '\n'
1003+}
1004+
1005+# Set colors to use with printf or echo -e if desired
1006+# W=White R=Red Y=Yello G=Green B=Blue C=Cyan (magenta) A=Aqua O=Orange GR=Grey DG=Dark Grey B=Black
1007+# AUB= Aubergine
1008+# Begin Colors
1009+# R=Reverse
1010+export ROW='\e[1;48;5;202m'
1011+export RWO='\e[38;5;208;48;5;255m'
1012+export RAUBW='\e[1;48;5;89m'
1013+export RWAUB='\e[1;38;5;89;48;5;255m'
1014+export RAUBW='\e[1;48;5;89;38;5;255m'
1015+export RYW='\e[1;5;43;37m'
1016+export RRW='\e[1;5;41;37m'
1017+export RGW='\e[1;5;42;37m'
1018+export RBW='\e[1;5;44;37m'
1019+export RGrW='\e[1;5;47;37m'
1020+export RCW='\e[1;5;45;37m'
1021+export RAW='\e[1;5;46;37m'
1022+export RYB='\e[5;43;30m'
1023+export RRB='\e[5;41;30m'
1024+export RGB='\e[5;42;30m'
1025+export RWB='\e[5;47;30m'
1026+export RGrB='\e[5;47;30m'
1027+export RCB='\e[5;45;30m'
1028+export RAB='\e[5;47;30m'
1029+
1030+# B=Bold (or bright)
1031+export BR='\e[1;31m'
1032+export BY='\e[1;33m'
1033+export BG='\e[1;32m'
1034+export BB='\e[1;34m'
1035+export BC='\e[1;35m'
1036+export BA='\e[1;36m'
1037+export BO='\e[38;5;202m'
1038+export GR='\e[0;37m'
1039+export DG='\e[1;30m'
1040+export BAUB='\e[1;38;5;89m'
1041+
1042+# R=Regular
1043+export RR='\e[0;31m'
1044+export RY='\e[0;33m'
1045+export RG='\e[0;32m'
1046+export RB='\e[0;34m'
1047+export RC='\e[0;35m'
1048+export RA='\e[0;36m'
1049+export RO='\e[38;5;208m'
1050+export RAUB='\e[38;5;89m'
1051+#End Colors
1052+
1053+# Special Characters
1054+#RT = ResetText
1055+export RT='\e[0m'
1056+#BU = Bold Underlined
1057+export BU='\e[1;4m'
1058+#BS = Backspace
1059+export BS='\b'
1060+
1061+
1062+
1063+#Function to get size of current terminal
1064+GetSize() {
1065+TTYTEST=$(stty size 2> /dev/null|awk '{print $2}')
1066+TheTTYResult=$?
1067+[[ ${TheTTYResult} -eq 0 ]] && export MYCOLUMNS=$(stty size 2>/dev/null|awk '{print $2}') && export MYROWS=$(stty size 2>/dev/null|awk '{print $1}')
1068+[[ ${TheTTYResult} -ne 0 ]] && export MYCOLUMNS=80 && export MYROWS=24
1069+export MIDCOL=$(($MYCOLUMNS/3))
1070+export MIDROW=$(($MYROWS/2))
1071+}
1072+
1073+#Function to print OK or Fail based on return code
1074+StatusChk() {
1075+local RETVAL=$?
1076+GetSize
1077+[[ $RETVAL -eq 0 ]] && RES_COL=$(($MYCOLUMNS-12)) && printf "\e[${RES_COL}G${DG}[ ${RO}OK${DG} ]${RT}\n" && sleep .5
1078+[[ $RETVAL -ne 0 ]] && RES_COL=$(($MYCOLUMNS-12)) && printf "\e[${RES_COL}G${DG}[ ${RR}FAIL${DG} ]${RT}\n" && sleep 2
1079+}
1080+
1081+
1082+#Function to center Text
1083+CenterText() {
1084+GetSize
1085+local title=$(printf "$@")
1086+printf "%*s\n" $(((${#title}+$MYCOLUMNS)/2)) "$title"
1087+}
1088+
1089+#Function to center text w/o a carriage return
1090+CenterTextNoCR() {
1091+GetSize
1092+local title=$(printf "$@")
1093+printf "\r%*s" $(((${#title}+$MYCOLUMNS)/2)) "$title"
1094+}
1095+
1096+#Does a color fade of a symbol (#) that surounds a message
1097+FadeMsg() {
1098+themsg="${1}"
1099+echo;for i in $(seq 232 255);do printf "\e[38;5;${i}m#\e[0m";done;printf "${themsg}";for i in $(seq 255 -1 232);do printf "\e[38;5;${i}m#\e[0m";done;echo
1100+}
1101+
1102+# Tex-based wait wheel that uses pipes and dashes that spin
1103+Spinner() {
1104+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1105+ Spinner_Usage () { WaitProg_Usage; }
1106+ local TheMsg="${1}"
1107+ local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1108+ local bs=$'\b'
1109+ local ThePipes="|${bs} /${bs} —${bs} \\${bs}"
1110+ for pipe in $ThePipes;do
1111+ printf "\e[0m${TheMsg}\e[1;37m\e[$((${StrLen}+${i}))G ${pipe}\r\e[0m"
1112+ sleep .25
1113+ done
1114+ printf "\e[0m${TheMsg}\e[1;37m\e[$((${StrLen}+${i}))G |\r\e[0m"
1115+}
1116+
1117+# Text-based wait wheel that grows from one period to three
1118+Elipsis() {
1119+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1120+ Elipsis_Usage () { WaitProg_Usage; }
1121+ local TheMsg="${1}"
1122+ local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1123+ for i in {1..3};do
1124+ printf "\e[0m${TheMsg}\e[$((${StrLen}+${i}))G.\r\e[0m"
1125+ sleep .5
1126+ done
1127+ printf "${TheMsg} \r\e[0m"
1128+}
1129+
1130+# UTF8-based wait wheel which uses the Half-Black ball character
1131+
1132+Ball() {
1133+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1134+ Spinner_Usage () { WaitProg_Usage; }
1135+ local TheMsg="${1}"
1136+ local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1137+ local bs=$'\b'
1138+ for i in 0 3 1 2;do
1139+ printf "\e[0m${TheMsg}${RO}\e[$((${StrLen}))G \u25d${i}\r\e[0m"
1140+ sleep .25
1141+ done
1142+ printf "\e[0m${TheMsg}${RO}\e[$((${StrLen}+))G \u25d0\r\e[0m"
1143+}
1144+
1145+# UTF8-based wait wheel showing the time on a clock from 1 until 12
1146+# on the hour and half-hour
1147+Clock() {
1148+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1149+ Spinner_Usage () { WaitProg_Usage; }
1150+ local TheMsg="${1}"
1151+ local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1152+ local bs=$'\b'
1153+ for i in 50 5C 51 5D 52 5E 53 5F 54 60 55 61 56 62 57 63 58 64 59 65 5A 66 5B 67;do
1154+ printf "\e[0m${TheMsg}${BW}\e[$((${StrLen}))G \U1F5${i}\r\e[0m"
1155+ sleep .25
1156+ done
1157+ printf "\e[0m${TheMsg}${BW}\e[$((${StrLen}))G \U1F550\r\e[0m"
1158+
1159+}
1160+
1161+# UTF8-based wait wheel showing the six different sides of a die
1162+Dice() {
1163+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1164+ Spinner_Usage () { WaitProg_Usage; }
1165+ local TheMsg="${1}"
1166+ local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1167+ local bs=$'\b'
1168+ for i in {0..5};do
1169+ printf "\e[0m${TheMsg}${BW}\e[$((${StrLen}))G \u268${i}\r\e[0m"
1170+ sleep .45
1171+ done
1172+ printf "\e[0m${TheMsg}${BW}\e[$((${StrLen}))G \r\e[0m"
1173+}
1174+
1175+# UTF8-based wait wheel showing the different suits in a deck of cards
1176+Suits() {
1177+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1178+ Spinner_Usage () { WaitProg_Usage; }
1179+ local TheMsg="${1}"
1180+ local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1181+ local bs=$'\b'
1182+ for i in 60 63 65 66;do
1183+ printf "\e[0m${TheMsg}\e[$((${StrLen}))G ${BR}\u26${i} \r\e[0m"
1184+ sleep .45
1185+ done
1186+ printf "\e[0m${TheMsg}\e[$((${StrLen}))G \r\e[0m"
1187+}
1188+
1189+
1190+# UTF8-based wait wheel which uses the White Pointing Triangle
1191+# For use whilst waiting (typically called by function WaitProg)
1192+Triangle() {
1193+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1194+ Spinner_Usage () { WaitProg_Usage; }
1195+ local TheMsg="${1}"
1196+ local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1197+ local bs=$'\b'
1198+ local TheShapes="△${bs} ▷${bs} ▽${bs} ◁${bs}"
1199+ for shape in $TheShapes;do
1200+ printf "\e[0m${TheMsg}${RO}\e[$((${StrLen}+${i}))G ${shape}\r\e[0m"
1201+ sleep .25
1202+ done
1203+ printf "\e[0m${TheMsg}${RO}\e[$((${StrLen}+${i}))G △\r\e[0m"
1204+}
1205+
1206+#A utf8 spinner based on Upper Quadrant Circular Arc
1207+#For use whilst waiting (typically called by function WaitProg)
1208+Worm() {
1209+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1210+ Spinner_Usage () { WaitProg_Usage; }
1211+ local TheMsg="${1}"
1212+ local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1213+ local bs=$'\b'
1214+ Spacer=0
1215+ for i in {1..8};do
1216+ Spacer=$(($Spacer+4))
1217+ printf "\r\e[0m${TheMsg}${RO}\e[$((${StrLen}+${Spacer}))G ╭\r\e[0m"
1218+ sleep .25
1219+ printf "\r\e[0m${TheMsg}${RO}\e[$((${StrLen}+${Spacer}))G ╭╮\r\e[0m"
1220+ sleep .25
1221+ printf "\r\e[0m${TheMsg}${RO}\e[$((${StrLen}+${Spacer}))G ╮\r\e[0m"
1222+ sleep .25
1223+ printf "\r\e[0m${TheMsg}${RO}\e[$((${StrLen}+${Spacer}))G \r\e[0m"
1224+ sleep .25
1225+ done
1226+ for i in {1..8};do
1227+ Spacer=$(($Spacer-4))
1228+ printf "\r\e[0m${TheMsg}${RO}\e[$((${StrLen}+${Spacer}))G ╮\r\e[0m"
1229+ sleep .25
1230+ printf "\r\e[0m${TheMsg}${RO}\e[$((${StrLen}+${Spacer}))G ╭╮\r\e[0m"
1231+ sleep .25
1232+ printf "\r\e[0m${TheMsg}${RO}\e[$((${StrLen}+${Spacer}))G ╭ \r\e[0m"
1233+ sleep .25
1234+ printf "\r\e[0m${TheMsg}${RO}\e[$((${StrLen}+${Spacer}))G \r\e[0m"
1235+ sleep .25
1236+ done
1237+}
1238+
1239+
1240+# A CountDown timer for use whilst waiting (typically called by function WaitProg)
1241+# Pulls timer duration from wait message
1242+CountDown() {
1243+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1244+ local TheMsg="${1}"
1245+ local TheMsgClean=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\t//g' -e 's/\\n//g')
1246+ local TheMsgLen=${#TheMsgClean}
1247+ local TheMsgTime=${TheMsgClean//[ a-zA-Z]/}
1248+ local NumRegEx='^[0-9]+$'
1249+ [[ ${TheMsgTime} =~ $NumRegEx ]] || { printf "\n${BR}Error${BW}: Could not parse CountDown duration.\n\n${BY}Please ensure that the wait message includes a number to represent the duration\n(in seconds) that you want the CountDown to run.${RT}\n\n"; return 3; }
1250+ local TheMsgStr1=`echo ${TheMsg}|awk -F"${TheMsgTime}" '{print $1}'`
1251+ local TheMsgStr2=`echo ${TheMsg}|awk -F"${TheMsgTime}" '{print $2}'`
1252+ local TimeWord="seconds"
1253+ for i in $(seq $TheMsgTime -1 1);do
1254+ [[ $i -eq 1 ]] && printf "\r${TheMsgStr1}${i}${TheMsgStr2} "|sed 's/'"${TimeWord}"'/'"${TimeWord:0:(-1)}"'/g'
1255+ [[ $i -ne 1 ]] && printf "\r${TheMsgStr1}${i}${TheMsgStr2} "
1256+ sleep 1
1257+ done
1258+ TimerResult=$?
1259+ printf '\r\e[0mTimer Finished. \r\e[0m\n'
1260+ return $TimerResult
1261+}
1262+
1263+# Wait wheel that has the the little arc (aka worm) jumping and leaving letters
1264+# that eventually spell Ubuntu
1265+Ubuntu() {
1266+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1267+ Ubu_Usage () { WaitProg -h;return; }
1268+ local TheMsg="${1}"
1269+ local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1270+ Spacer=0
1271+ for i in {1..6};do
1272+ [[ $i -eq 1 ]] && Spacer=0 || Spacer=$((${Spacer}+5))
1273+ [[ $i -eq 1 ]] && SC='U'
1274+ [[ $i -eq 2 ]] && SC='b'
1275+ [[ $i -eq 3 ]] && SC='u'
1276+ [[ $i -eq 4 ]] && SC='n'
1277+ [[ $i -eq 5 ]] && SC='t'
1278+ [[ $i -eq 6 ]] && SC='u'
1279+ printf "\r\e[0m${TheMsg}\e[$((${StrLen}+${Spacer}))G ╭ \r\e[0m\r\e[0m"
1280+ sleep .15
1281+ printf "\r\e[0m${TheMsg}\e[$((${StrLen}+${Spacer}))G ${RO}${SC}${RT}\r\e[0m\r\e[0m"
1282+ sleep .15
1283+ printf "\r\e[0m${TheMsg}\e[$((${StrLen}+${Spacer}))G ${RO}${SC}${RT} ╮\r\e[0m\r\e[0m"
1284+ sleep .15
1285+ printf "\r\e[0m${TheMsg}\e[$((${StrLen}+${Spacer}))G ${RO}${SC}${RT} \r\e[0m\r\e[0m"
1286+ sleep .15
1287+ done
1288+ sleep .5
1289+ printf '\r'"${TheMsg}"' \r\e[0m'
1290+}
1291+
1292+# Wait wheel that has the the little arc (aka worm) jumping and leaving the Ubuntu
1293+# Circle of friends logo
1294+
1295+Logo() {
1296+ [[ ${1} = '-h' || ${1} = '--help' ]] && { WaitProg -h ; return; }
1297+ Ubu2_Usage () { WaitProg -h;return; }
1298+ local TheMsg="${1}"
1299+ local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1300+ Spacer=0
1301+ for i in {1..6};do
1302+ [[ $i -eq 1 ]] && Spacer=0 || Spacer=$((${Spacer}+5))
1303+ SC='\ue0ff'
1304+ printf "\r\e[0m${TheMsg}\e[$((${StrLen}+${Spacer}))G ╭ \r\e[0m\r\e[0m"
1305+ sleep .15
1306+ printf "\r\e[0m${TheMsg}\e[$((${StrLen}+${Spacer}))G ${RO}${SC}${RT}\r\e[0m\r\e[0m"
1307+ sleep .15
1308+ printf "\r\e[0m${TheMsg}\e[$((${StrLen}+${Spacer}))G ${RO}${SC}${RT} ╮\r\e[0m\r\e[0m"
1309+ sleep .15
1310+ printf "\r\e[0m${TheMsg}\e[$((${StrLen}+${Spacer}))G ${RO}${SC}${RT} \r\e[0m\r\e[0m"
1311+ sleep .15
1312+ done
1313+ sleep .5
1314+ printf '\r'"${TheMsg}"' \r\e[0m'
1315+}
1316+
1317+WaitProg() {
1318+ WaitProg_Usage () {
1319+ local usage="
1320+ ${BY}${FUNCNAME%_*}${RT}
1321+
1322+ ${BU}Purpose${RT}
1323+ Displays a user specified message and wait wheel, while user specified programs run in background
1324+
1325+ ${BU}Usage${RT}
1326+ ${FUNCNAME%_*} [OPTIONS] <prog>
1327+
1328+ ${BU}Options${RT}
1329+ ${BC}-m:${RT} Message to display along with wait wheel
1330+ ${BC}-s${RT} Use the \"Spinner\" wait wheel
1331+ ${BC}-S${RT} Use the \"Suits\" (Cards) wait wheel (UTF8)
1332+ ${BC}-e${RT} Use the \"Elipsis\" wait wheel
1333+ ${BC}-b${RT} Use the \"Ball\" wait wheel (UTF8)
1334+ ${BC}-t${RT} Use the \"Triangle\" wait wheel (UTF8)
1335+ ${BC}-w${RT} Use the \"Worm\" wait wheel (UTF8)
1336+ ${BC}-u${RT} Use the \"Ubuntu\" text wait wheel
1337+ ${BC}-U${RT} Use the \"Ubuntu Logo\" (Circle of Friends) wait wheel (UTF8)
1338+ ${BC}-c${RT} Use the \"CountDown\" timer wait wheel
1339+ ${BC}-C${RT} Use the \"Clocks\" timer wait wheel (UTF8)
1340+ ${BC}-n${RT} NoProg Option - Valid only for CountDown wait wheel
1341+ ${BC}-d${RT} Use the \"Duration\" timer wait wheel
1342+ ${BC}-D${RT} Use the \"Dice\" timer wait wheel (UTF8)
1343+
1344+ ${BU}Notes${RT}
1345+ -: Wait wheel types are mutually exclusive
1346+ -: If Ubuntu Logo wait wheel does not render, ensure your font is set to \"Ubuntu Mono\"
1347+ -: For the CountDown wait wheel, the duration is specified (in seconds) in the
1348+ wait message e.g. -m \"Waiting for 30 seconds\"
1349+ -: To just do a CountDown without running a program in the background, use the -c
1350+ (CountDown) and -n (NoProg) options together
1351+
1352+ ${BU}Examples${RT}
1353+ ${BY}${FUNCNAME%_*} ${BC}-s -m \"Waiting for sleep to finish\"${RT} ${BW}sleep 20${RT}
1354+ Will run command \"sleep 20\" in background, while foreground displays a message and
1355+ the \"Spinner\" wait wheel
1356+ ${BY}${FUNCNAME%_*} ${BC}-c -n -m \"Waiting 90 seconds after networking restart\" ${RT}
1357+ Will countdown from 90 to 1 using the message specified. The number in the message (90)
1358+ decrements to 1, after which a \"Timer Finished\" message will replace the provided
1359+ message and the script will continue.
1360+
1361+ \r\e[0m"
1362+ [[ $(which setterm) ]] && setterm --cursor on
1363+ clear
1364+ printf "${usage}" 2>&1;
1365+ }
1366+ TRUE=true
1367+ FALSE=false
1368+ NoProg=${FALSE}
1369+ local MEMsg="\n${BR}Error${BW}: Wait wheel types are mutually exclusive${RT}\n\n"
1370+ local OPTIND o m s S e b t w u U c C d D n h
1371+ while getopts ":m:sSebtwuUcCdDnh" o; do
1372+ case "${o}" in
1373+ m) local TheMsg="${OPTARG}"
1374+ ;;
1375+ s) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Spinner"
1376+ ;;
1377+ S) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Suits"
1378+ ;;
1379+ e) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Elipsis"
1380+ ;;
1381+ b) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Ball"
1382+ ;;
1383+ t) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Triangle"
1384+ ;;
1385+ w) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Worm"
1386+ ;;
1387+ u) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Ubuntu"
1388+ ;;
1389+ U) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Logo"
1390+ ;;
1391+ c) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="CountDown"
1392+ ;;
1393+ C) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Clock"
1394+ ;;
1395+ d) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Duration"
1396+ ;;
1397+ D) [[ -n ${WAIT_WHEEL} ]] && { printf ${MEMsg};return; } || local WAIT_WHEEL="Dice"
1398+ ;;
1399+ n) [[ ${WAIT_WHEEL} = "CountDown" ]] && local NoProg=${TRUE} || { printf "\n${BR}Error${BW}: NoProg option requires the CountDown (-c) options${RT}\n\n";return 1; }
1400+ ;;
1401+ h) ${FUNCNAME%_*}_Usage
1402+ return 0
1403+ ;;
1404+ \?|*) [[ $OPTIND -eq 2 ]] && { OPTIND=1; ${FUNCNAME%_*}_Usage; return; } || printf "\n${BR}Error${RT}: invalid option specified\n"
1405+ ;;
1406+ esac
1407+ done
1408+
1409+ shift $((OPTIND-1))
1410+ trap 'setterm --cursor on; return' EXIT
1411+ unset ETStr
1412+ [[ -z ${WAIT_WHEEL} ]] && local WAIT_WHEEL="Spinner"
1413+ [[ $(which setterm) ]] && setterm --cursor off
1414+ if [[ ${NoProg} = ${FALSE} ]];then
1415+ local TheCmd="${@}"
1416+ local CmdName=${TheCmd% *}
1417+ local CmdName=${CmdName^}
1418+
1419+ [[ ${WAIT_WHEEL} != CountDown && ! -n ${TheMsg} ]] && local TheMsg="Waiting on ${CmdName} to complete"
1420+ [[ ${WAIT_WHEEL} = CountDown && -z ${TheMsg} ]] && { printf "\n${BR}Error${BW}: CountDown option requires the message (-m) option${RT}\n\n";[[ $(which setterm) ]] && setterm --cursor on;return 2; }
1421+ [[ $EUID -ne 1 ]] && LOG=$HOME/WaitProg.${TheCmd% *}.log || LOG=/var/log/WaitProg.${TheCmd% *}.log
1422+ TheProg() { $TheCmd &>$LOG & }
1423+ TheProg &>/dev/null
1424+ pid=$!
1425+ fi
1426+ if [[ ${WAIT_WHEEL} != "CountDown" ]];then
1427+ trap "kill $pid 2>/dev/null" EXIT
1428+ [[ ${WAIT_WHEEL} = "Duration" ]] && local StrLen=$(echo $TheMsg|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\n//g'|wc -c)
1429+ while kill -0 $pid 2>/dev/null;do
1430+ if [[ ${WAIT_WHEEL} != "Duration" ]];then
1431+ $WAIT_WHEEL "$TheMsg"
1432+ else
1433+ [[ -z $DTime ]] && local DTime=0
1434+ [[ ${WAIT_WHEEL} = Duration ]] & local ETStr="${DG}[ Elapsed Time: ${RT}${DTime}s${DG} ]\e[0m"
1435+ printf "\r\e[0m${TheMsg}\e[$((${StrLen}))G ${ETStr} \r\e[0m"
1436+ local DTime=$((${DTime}+1))
1437+ sleep 1
1438+ fi
1439+ done
1440+ else
1441+ $WAIT_WHEELn "$TheMsg"
1442+ TimerRC=$?
1443+ if [[ ${TimerRC} -eq 3 ]];then
1444+ printf "\n${BR}Error${BW}: Could not parse CountDown duration.\n\n${BY}Please ensure that the wait message includes a number to represent the duration\n(in seconds) that you want the CountDown to run.${RT}\n\n"
1445+ [[ $(which setterm) ]] && setterm --cursor on
1446+ return 1
1447+ else
1448+ if [[ ${NoProg} = ${FALSE} ]];then
1449+ wait $pid
1450+ local ProgResult=$?
1451+ [[ $ProgResult -eq 0 ]] && printf "\r\e[1;37m${CmdName^}\e[0m has completed \e[1;32msuccessfully\e[0m \n" || printf "\e[1;37m\r${CmdName^}\e[0m completed with \e[1;31merrors\e[0m \n"
1452+ [[ $(which setterm) ]] && setterm --cursor on
1453+ return $ProgResult
1454+ fi
1455+ fi
1456+ fi
1457+ if [[ ${NoProg} = ${FALSE} ]];then
1458+ wait $pid
1459+ local ProgResult=$?
1460+ trap - EXIT
1461+ [[ ${WAIT_WHEEL} = Duration ]] && local ETStr="${DG}[ Elapsed Time: ${RT}${DTime}s${DG} ]\e[0m"
1462+ [[ ${WAIT_WHEEL} != CountDown ]] && [[ $ProgResult -eq 0 ]] && printf "\r\e[1;37m${CmdName^}\e[0m has completed \e[1;32msuccessfully ${ETStr}\e[0m \n" || printf "\e[1;37m\r${CmdName^}\e[0m completed with \e[1;31merrors ${ETStr}\e[0m \n"
1463+ [[ $(which setterm) ]] && setterm --cursor on
1464+ [[ ${WAIT_WHEEL} != CountDown ]] && return $ProgResult
1465+ fi
1466+} 2>/dev/null #Used to suppress Job Control Message of Done
1467+
1468+#Function to replace parameters in scripts
1469+ParamSearch() {
1470+ParamSearch_Usage () {
1471+local usage="
1472+${BY}${FUNCNAME%_*}${RT}
1473+
1474+${BU}Purpose${RT}
1475+Performs case-insensitive search for files which set the specified parameter.
1476+Displays the filename, line number, and parameter. Can also replace parameters
1477+or delete lines which set the specified parameter.
1478+
1479+${BU}Usage${RT}
1480+${FUNCNAME%_*} [OPTIONS] Old_Parameter <New_Parameter>
1481+
1482+${BU}Options${RT}
1483+${BC}-p${RT} Path to search (Default: Current/working directory)
1484+${BC}-t${RT} File Type/Extension e.g. sh or txt. (Default: All FIles)
1485+${BC}-l${RT} Perform a \"loose\" search i.e. match any line containing Old_Parameter
1486+ and an equal sign i.e. Old_Parameter.*= (Default: False)
1487+${BC}-r${RT} Replace Old_Parameter= with New_Parameter= (Default: False)
1488+${BC}-d${RT} Delete <Old_Parameter> (Default: False)
1489+
1490+${BU}Notes${RT}
1491+-: Specifying a path or file type makes search non-recursive
1492+-: Replace, Delete, and Loose-search options are mutually exclusive
1493+-: All Replace and Delete options use strict search
1494+
1495+${BU}Examples${RT}
1496+${BY}${FUNCNAME%_*} ${BW}ob_num${RT}
1497+Performs a strict, case-insensitive, recursive search, starting in the current
1498+working directory, ${BG}displaying${RT} all files which set the parameter ${BW}ob_num=${RT}
1499+
1500+${BY}${FUNCNAME%_*} ${BC}-l${RT} ${BW}ob_num${RT}
1501+Performs a loose, case-insensitive, recursive search, starting in the current
1502+working directory, ${BG}displaying${RT} all files which set the parameter ${BW}ob_num*=${RT}
1503+
1504+${BY}${FUNCNAME%_*} ${BC}-p /svr/obinstall -t sh${RT} ${BW}ob_num${RT}
1505+Performs a strict, case-insensitive, non-recursive search of /srv/obinstall,
1506+${BG}displaying${RT} only *.sh files which set the parameter ${BW}ob_num=${RT}
1507+
1508+${BY}${FUNCNAME%_*} ${BC}-d${RT} ${BW}ob_num${RT}
1509+Performs a strict, case-insensitive, recursive search, starting in the current
1510+working directory, ${RR}deleting all lines${RT} which set the parameter ${BW}ob_num=${RT}
1511+
1512+${BY}${FUNCNAME%_*} ${BC}-r${RT} ${BW}ob_num OBNUMBER${RT}
1513+Performs a strict, case-insensitive, recursive search, starting in the current
1514+working directory, ${BY}replacing all instances${RT} of parameter ${BW}ob_num=${RT}
1515+with ${BW}OBNUMBER=${RT}
1516+
1517+
1518+"
1519+clear
1520+printf "${usage}" 2>&1;
1521+}
1522+TRUE=true
1523+FALSE=false
1524+DelParam=${FALSE}
1525+RepParam=${FALSE}
1526+LooseSearch=${FALSE}
1527+local OPTIND o p t d r l h
1528+while getopts ":p:t:drlh" o; do
1529+ case "${o}" in
1530+ p) [[ ! -d "${OPTARG}" ]] && { printf "\n${BR}Error${RT}: Provide path of \"${BW}${OPTARG}${RT}\" does not exist!${RT}\n\n";return; } || local ThePath="${OPTARG}/"
1531+ ;;
1532+ t) local FileType="*.${OPTARG}"
1533+ ;;
1534+ d) [[ ${RepParam} = ${TRUE} || ${LooseSearch} = ${TRUE} ]] && { printf "\n${BR}Error${BW}: Replace, Delete, and Loose-Search options are mutually exclusive${RT}\n\n";${FUNCNAME%_*}_Usage;return; } || local DelParam="${TRUE}"
1535+ ;;
1536+ r) [[ ${DelParam} = ${TRUE} || ${LooseSearch} = ${TRUE} ]] && { printf "\n${BR}Error${BW}: Replace, Delete, and Loose-Search options are mutually exclusive${RT}\n\n";${FUNCNAME%_*}_Usage;return; } || local RepParam="${TRUE}"
1537+ ;;
1538+ l) [[ ${DelParam} = ${TRUE} || ${RepParam} = ${TRUE} ]] && { printf "\n${BR}Error${BW}: Replace, Delete, and Loose-Search options are mutually exclusive${RT}\n\n";${FUNCNAME%_*}_Usage;return; } || local LooseSearch="${TRUE}"
1539+ ;;
1540+ h) ${FUNCNAME%_*}_Usage
1541+ return 0
1542+ ;;
1543+ \?|*) [[ $OPTIND -eq 2 ]] && { OPTIND=1; ${FUNCNAME%_*}_Usage; return; } || printf "\n${BR}Error${RT}: invalid option specified\n"
1544+ ;;
1545+ esac
1546+done
1547+shift $((OPTIND-1))
1548+[[ -z ${ThePath} && -z ${FileType} ]] && { local RSearchType='recursive';local ThePath=""; local FileType=""; local FileString='all files'; local PrintPath="${PWD}"; }
1549+[[ ! -z ${ThePath} || ! -z ${FileType} ]] && { [[ -z ${ThePath} ]] && local ThePath="${PWD}/";[[ -z ${FileType} ]] && local FileType='*.*';local RSearchType='non-recursive';local FileString=''"${FileType}"' file types'; local PrintPath="${ThePath}"; }
1550+[[ ! -z "${1}" ]] && local OldParam="${1}"
1551+[[ ! -z "${2}" ]] && local NewParam="${2}"
1552+[[ ${LooseSearch} = ${TRUE} ]] && { local TheString=''${OldParam}'.*=';local SearchType="loose"; } || { local TheString=''${OldParam}'=';local SearchType="strict"; }
1553+printf "\nPerforming a ${BW}${SearchType}${RT}, ${BW}${RSearchType}${RT} search of ${BW}${PrintPath}${RT} for ${BW}${FileString}${RT} which${RO} set${RT} the parameter: \"${BW}${TheString}${RT}\"\n\n"
1554+printf '${RT}'
1555+[[ ${LooseSearch} = ${TRUE} ]] && grep -wnriE ''${OldParam}'.*=' ${ThePath}${FileType} || grep -wnriE ''${OldParam}'=' ${ThePath}${FileType}
1556+if [[ ${DelParam} = ${TRUE} ]];then
1557+ local IFS=$'\n'
1558+ while true; do
1559+ read -e -i "no" -r -p "Are you sure you really want to delete these lines? Type n/q to quit [y/n/q]: " delline
1560+ case $delline in
1561+ [Yy]* ) for i in $(grep -wlirE ''${OldParam}'=' ${ThePath}${FileType});do
1562+ printf "\n${BW}Deleting${RT} ${ROW}${OldParam}${RT} from ${BW}${i}${RT}"
1563+ sed -i.orig '/'${OldParam}'=/d' ${i};StatusChk
1564+ done
1565+ break
1566+ ;;
1567+ [Nn]* ) echo "No Changes Made"
1568+ break
1569+ ;;
1570+ * ) echo "Please enter y,n, or q (y/n/q)";sleep 2;;
1571+ esac
1572+ done
1573+elif [[ ${RepParam} = ${TRUE} ]];then
1574+ local IFS=$'\n'
1575+ for i in $(grep -wlirE ''${OldParam}'=' ${ThePath}${FileType});do
1576+ printf "Replacing ${ROW}${OldParam}${RT} with ${RWO} ${NewParam}${RT} in ${BW}${i}${RT}"
1577+ sed -i.orig 's/'${NewParam}'=/'${OldParam}'=/g' ${i};StatusChk
1578+ done
1579+fi
1580+
1581+}
1582+
1583+#Function to replace variables in scripts
1584+VarSearch() {
1585+VarSearch_Usage () {
1586+local usage="
1587+${BY}${FUNCNAME%_*}${RT}
1588+
1589+${BU}Purpose${RT}
1590+Performs case-insensitive search for files which use the specified variable.
1591+Displays the filename, line number, and variable. Can also replace variables
1592+or delete lines which use the specified variable.
1593+
1594+${BU}Usage${RT}
1595+${FUNCNAME%_*} [OPTIONS] Old_Variable <New_Variable>
1596+
1597+${BU}Options${RT}
1598+${BC}-p${RT} Path to search (Default: Current/working directory)
1599+${BC}-t${RT} File Type/Extension e.g. sh or txt. (Default: All FIles)
1600+${BC}-l${RT} Perform a \"loose\" search i.e. match any line containing Old_Variable
1601+ and an equal sign i.e. Old_Variable.* (Default: False)
1602+${BC}-r${RT} Replace Old_Variable= with New_Variable= (Default: False)
1603+${BC}-d${RT} Delete <Old_Variable> (Default: False)
1604+
1605+${BU}Notes${RT}
1606+-: Specifying a path or file type makes search non-recursive
1607+-: Replace, Delete, and Loose-search options are mutually exclusive
1608+-: All Replace and Delete options use strict search
1609+
1610+${BU}Examples${RT}
1611+${BY}${FUNCNAME%_*} ${BW}ob_num${RT}
1612+Performs a strict, case-insensitive, recursive search, starting in the current
1613+working directory, ${BG}displaying${RT} all files which use the variables ${BW}\${ob_num}${RT}
1614+and ${BW}\$ob_num${RT}
1615+
1616+${BY}${FUNCNAME%_*} ${BC}-l${RT} ${BW}ob_num${RT}
1617+Performs a loose, case-insensitive, recursive search, starting in the current
1618+working directory, ${BG}displaying${RT} all files which use the variables ${BW}\${ob_num}${RT}
1619+and ${BW}\$ob_num${RT}
1620+
1621+
1622+${BY}${FUNCNAME%_*} ${BC}-p /svr/obinstall -t sh${RT} ${BW}ob_num${RT}
1623+Performs a strict, case-insensitive, non-recursive search of /srv/obinstall,
1624+${BG}displaying${RT} only *.sh files which use the variables ${BW}\${ob_num}${RT} and ${BW}\$ob_num${RT}
1625+
1626+
1627+${BY}${FUNCNAME%_*} ${BC}-d${RT} ${BW}ob_num${RT}
1628+Performs a strict, case-insensitive, recursive search, starting in the current
1629+working directory, ${RR}deleting all lines${RT} which use the variables ${BW}\${ob_num}${RT}
1630+and ${BW}\$ob_num${RT}
1631+
1632+${BY}${FUNCNAME%_*} ${BC}-r${RT} ${BW}ob_num OBNUMBER${RT}
1633+Performs a strict, case-insensitive, recursive search, starting in the current
1634+working directory, ${BY}replacing all instances${RT} of variables ${BW}\${ob_num}${RT}
1635+and ${BW}\$ob_num${RT} with ${BW}\${OBNUMBER}${RT}
1636+
1637+
1638+"
1639+clear
1640+printf "${usage}"
1641+}
1642+TRUE=true
1643+FALSE=false
1644+DelVar=${FALSE}
1645+RepVar=${FALSE}
1646+LooseSearch=${FALSE}
1647+local OPTIND o p t d r l h
1648+while getopts ":p:t:drlh" o; do
1649+ case "${o}" in
1650+ p) [[ ! -d "${OPTARG}" ]] && { printf "\n${BR}Error${RT}: Provide path of \"${BW}${OPTARG}${RT}\" does not exist!${RT}\n\n";return; } || local ThePath="${OPTARG}/"
1651+ ;;
1652+ t) local FileType="*.${OPTARG}"
1653+ ;;
1654+ d) [[ ${RepVar} = ${TRUE} || ${LooseSearch} = ${TRUE} ]] && { printf "\n${BR}Error${BW}: Replace, Delete, and Loose-Search options are mutually exclusive${RT}\n\n";${FUNCNAME%_*}_Usage;return; } || local DelVar="${TRUE}"
1655+ ;;
1656+ r) [[ ${DelVar} = ${TRUE} || ${LooseSearch} = ${TRUE} ]] && { printf "\n${BR}Error${BW}: Replace, Delete, and Loose-Search options are mutually exclusive${RT}\n\n";${FUNCNAME%_*}_Usage;return; } || local RepVar="${TRUE}"
1657+ ;;
1658+ l) [[ ${DelVar} = ${TRUE} || ${RepVar} = ${TRUE} ]] && { printf "\n${BR}Error${BW}: Replace, Delete, and Loose-Search options are mutually exclusive${RT}\n\n";${FUNCNAME%_*}_Usage;return; } || local LooseSearch="${TRUE}"
1659+ ;;
1660+ h) ${FUNCNAME%_*}_Usage
1661+ return 0
1662+ ;;
1663+ \?|*) [[ $OPTIND -eq 2 ]] && { OPTIND=1; ${FUNCNAME%_*}_Usage; return; } || printf "\n${BR}Error${RT}: invalid option specified\n"
1664+ ;;
1665+ esac
1666+done
1667+shift $((OPTIND-1))
1668+[[ -z ${ThePath} && -z ${FileType} ]] && { local RSearchType='recursive';local ThePath=""; local FileType=""; local FileString='all files'; local PrintPath="${PWD}"; }
1669+[[ ! -z ${ThePath} || ! -z ${FileType} ]] && { [[ -z ${ThePath} ]] && local ThePath="${PWD}/";[[ -z ${FileType} ]] && local FileType='*.*';local RSearchType='non-recursive';local FileString=''"${FileType}"' file types'; local PrintPath="${ThePath}"; }
1670+[[ ! -z "${1}" ]] && local OldVar="${1}"
1671+[[ ! -z "${2}" ]] && local NewVar="${2}"
1672+[[ ${LooseSearch} = ${TRUE} ]] && { local TheString='${'${OldVar}'.*}';local SearchType="loose"; } || { local TheString='${'${OldVar}'}';local SearchType="strict"; }
1673+printf "\nPerforming a ${BW}${SearchType}${RT}, ${BW}${RSearchType}${RT} search of ${BW}${PrintPath}${RT} for ${BW}${FileString}${RT} which${RO} set${RT} the variable: \"${BW}${TheString}${RT}\"\n\n"
1674+printf '${RT}'
1675+[[ ${LooseSearch} = ${TRUE} ]] && grep -wnriE '\$\{'${OldVar}'.*\}|\$'${OldVar}'.*' ${ThePath}${FileType} || grep -wnriE '\$\{'${OldVar}'\}|\$\'${OldVar}'' ${ThePath}${FileType}
1676+if [[ ${DelVar} = ${TRUE} ]];then
1677+ local IFS=$'\n'
1678+ while true; do
1679+ read -e -i "no" -r -p "Are you sure you really want to delete these lines? Type n/q to quit [y/n/q]: " delline
1680+ case $delline in
1681+ [Yy]* ) for i in $(grep -wlirE '\$\{'${OldVar}'\}|\$'${OldVar}'' ${ThePath}${FileType});do
1682+ printf "\n${BW}Deleting lines that contain${RT} ${ROW}\${${OldVar}}${RT} from ${BW}${i}${RT}"
1683+ sed -i.orig-1 '/\$\{'${OldVar}'\}/d' ${i};StatusChk
1684+ printf "\n${BW}Deleting lines that contain${RT} ${ROW}\$${OldVar}${RT} from ${BW}${i}${RT}"
1685+ sed -i.orig-2 '/\$'${OldVar}'/d' ${i};StatusChk
1686+ done
1687+ break
1688+ ;;
1689+ [Nn]* ) echo "No Changes Made"
1690+ break
1691+ ;;
1692+ * ) echo "Please enter y,n, or q (y/n/q)";sleep 2;;
1693+ esac
1694+ done
1695+elif [[ ${RepVar} = ${TRUE} ]];then
1696+ local IFS=$'\n'
1697+ for i in $(grep -wlirE '\$\{'${OldVar}'\}|\$'${OldVar}'' ${ThePath}${FileType});do
1698+ printf "Replacing variable ${ROW}\${${OldVar}}${RT} with ${RWO}\${${NewVar}}${RT} in ${BW}${i}${RT}"
1699+ sed -i.orig-1 's/'${NewVar}'/'${OldVar}'/g' ${i};StatusChk
1700+ printf "Replacing variable ${ROW}\${$OldVar}${RT} with ${RWO}\$${NewVar}${RT} in ${BW}${i}${RT}"
1701+ sed -i.orig-1 's/'${NewVar}'/'${OldVar}'/g' ${i};StatusChk
1702+
1703+ done
1704+fi
1705+
1706+}
1707+
1708+
1709+#Function to draw boxes with UTF8 Characters
1710+DrawBox() {
1711+ DrawBox_Usage () {
1712+ local usage="
1713+ ${BY}${FUNCNAME%_*}${RT}
1714+
1715+ ${BU}Purpose${RT}
1716+ Displays a box with rounded corners using UTF8 Box Drawing Characters
1717+
1718+ ${BU}Usage${RT}
1719+ ${FUNCNAME%_*} [OPTIONS]
1720+
1721+ ${BU}Options${RT}
1722+ ${BC}-W:${RT} Width of Box (~Columns)
1723+ ${BC}-H:${RT} Height of Box (in Rows)
1724+ ${BC}-r:${RT} Use \"rounded\" corners
1725+ ${BC}-s:${RT} Use \"square\" corners
1726+ ${BC}-c:${RT} Line Color
1727+ ${BC}-f:${RT} Fill Color
1728+ ${BC}-t:${RT} Text (Experimental)
1729+ ${BC}-h${RT} This Message
1730+
1731+
1732+ ${BU}Notes${RT}
1733+ -: Width not exactly based on columns due size of UTF Box drawing character overlap
1734+
1735+ ${BU}Examples${RT}
1736+ ${BY}${FUNCNAME%_*} ${BC}-W 40 -H 6${RT}
1737+ Will draw a box that is 40 columns wide and 6 rows high
1738+ " # Ending quote for usage parameter
1739+ clear
1740+ printf "${usage}" 2>&1;
1741+ }
1742+
1743+ #Rounded Corners UTF8 Box Drawing Characters
1744+ export RBX_HOR='\u2500'
1745+ [[ ! -z ${SSH_TTY} ]] && export RBX_VER='\u2503' || export RBX_VER='\u2502'
1746+ export RBX_UL='\u256D'
1747+ export RBX_UR='\u256E'
1748+ export RBX_LL='\u2570'
1749+ export RBX_LR='\u256F'
1750+ #Square Corners UTF8 Box Drawing Characters
1751+ export SBX_HOR='\u2501'
1752+ export SBX_VER='\u2503'
1753+ export SBX_UL='\u250F'
1754+ export SBX_UR='\u2513'
1755+ export SBX_LL='\u2517'
1756+ export SBX_LR='\u251B'
1757+ #This hack is required to get the current cursor position after we draw top of box
1758+ #so we know where align the sides
1759+ GetCurPos() {
1760+ [[ $(echo ${@}|grep -iqE '\-r|\-R';echo $?) -eq 0 ]] && local PRINTROW=${TRUE} || local PRINTROW=${FALSE}
1761+ [[ $(echo ${@}|grep -iqE '\-c|\-C';echo $?) -eq 0 ]] && local PRINTCOL=${TRUE} || local PRINTCOL=${FALSE}
1762+ local oldstty=$(stty -g)
1763+ stty raw -echo min 0
1764+ printf '\e[6n' > $(tty)
1765+ IFS=';' read -r -d R -a CURPOS
1766+ stty $oldstty
1767+ export CUR_ROW=$((${CURPOS[0]:2} - 1))
1768+ export CUR_COL=$((${CURPOS[1]} - 1))
1769+ [[ ${PRINTROW} = $TRUE ]] && echo $CUR_ROW
1770+ [[ ${PRINTCOL} = $TRUE ]] && echo $CUR_COL
1771+ }
1772+
1773+ #Unset any existing BOX_ Vars
1774+ for var in $(set |grep -oE '^BOX.*=');do unset ${var:0:(-1)} unset $i 2>/dev/null;done
1775+
1776+ #Set Space Variables
1777+ #Space
1778+ export BOX_RS='\u0020'
1779+ #Punctuation Space
1780+ export BOX_RS='\u2008'
1781+ #Regular Space
1782+ export BOX_TS='\u2009'
1783+ #Hairline Space
1784+ export BOX_HS='\u200A'
1785+ #Zero Space
1786+ export BOX_ZS='\u200B'
1787+ #NBSP
1788+ export BOX_NS='\u00A0'
1789+ #Narrow NBSP
1790+ export BOX_NN='\u202F'
1791+ #Zero NBSP
1792+ export BOX_ZN='\uFEFF'
1793+
1794+ local OPTIND o W H c f s r t h
1795+ while getopts ":W:H:c:f:srt:h" o; do
1796+ case "${o}" in
1797+ W) local BOX_WID="${OPTARG}"
1798+ ;;
1799+ H) local BOX_HGT="${OPTARG}"
1800+ ;;
1801+ c) local BOX_COL="${OPTARG}"
1802+ ;;
1803+ f) local BOX_FIL="${OPTARG}"
1804+ ;;
1805+ s) [[ -n ${BOX_STL} ]] && printf "\n${BR}Error${RT}: Box corner styles are mutually exclusive\n" || local BOX_STL="SBX"
1806+ ;;
1807+ r) [[ -n ${BOX_STL} ]] && printf "\n${BR}Error${RT}: Box corner styles are mutually exclusive\n" || local BOX_STL="RBX"
1808+ ;;
1809+ t) BOX_TXT="${OPTARG}"
1810+ ;;
1811+ h) ${FUNCNAME%_*}_Usage
1812+ return 0
1813+ ;;
1814+ \?) [[ $OPTIND -eq 2 ]] && { OPTIND=1; ${FUNCNAME%_*}_Usage; return; }
1815+ ;;
1816+ *) printf "\n${BR}Error${RT}: invalid option specified\n"
1817+ ;;
1818+ esac
1819+ done
1820+ shift $((OPTIND-1))
1821+
1822+ [[ -z ${BOX_STL} ]] && local BOX_STL="RBX"
1823+ [[ ${BOX_STL} = "RBX" ]] && SSH_FIX=''
1824+ #Copy Current Round or Square Variables to BOX based on \$BOX_STL variable
1825+ for var in $(set |grep -E '^'${BOX_STL}'_');do eval export ${var/${BOX_STL}/BOX};done
1826+ [[ -n ${BOX_FIL} ]] && export BOX_IN='\u00A0' || export BOX_IN=''
1827+ #Finally, draw the box
1828+ #Print Upper Corners and top horizontal bits. Get cursor position to determine right hand margin
1829+ # Width based on provided number
1830+ # Note: - eval used for some parts because of the WID, HGT, and MGN variables
1831+ { printf ''${BOX_COL}${BOX_UL}${BOX_SP}${RT}'';eval printf '${BOX_COL}${BOX_HOR}${RT}%.0s' {0..$BOX_WID};printf ${BOX_COL}${SSH_FIX}${BOX_UR}${RT};export BOX_MGN='\e['$(GetCurPos -c)'G';printf '\n'; }
1832+ #Print vertical pieces, with right side determined by BOX_MGN which is set by GetCurPos
1833+ #Number of times based on provided Height
1834+ if [[ -n ${BOX_FIL} ]];then
1835+ #eval "export HGT=${BOX_HGT}"
1836+ for i in $(eval 'seq 0 ${BOX_HGT}');do
1837+ { printf ''${BOX_COL}${BOX_VER}${RT}${SSH_SPACE}'';[[ -z ${BOX_TXT_START} ]] && export BOX_TXT_START='\e['$(GetCurPos -c)'G';eval printf '${BOX_FIL}${BOX_IN}${RT}%.0s' {0..$BOX_WID};printf ${BOX_COL}${BOX_VER}${RT};export BOX_MGN='\e['$(GetCurPos -c)'G';printf '\n'; }
1838+ done
1839+ else
1840+ { eval printf '${BOX_COL}${BOX_VER}${BOX_FIL}${BOX_MGN}${BOX_FIL}${RT}${BOX_COL}${BOX_VER}${RT}\\n%.0s' {0..$BOX_HGT}; }
1841+ fi
1842+ #Print Lower corners and bottom horizontal bits
1843+ { printf ''${BOX_COL}${BOX_LL}${BOX_SP}${RT}'';eval printf '${BOX_COL}${BOX_HOR}${RT}%.0s' {0..$BOX_WID};printf ''${BOX_COL}${SSH_FIX}${BOX_LR}${RT}'\n'; }
1844+ if [[ ! -z "${BOX_TXT}" ]];then
1845+ #Clean out any color codes so we get the true length
1846+ local BOX_TXT_CLN=$(echo ${BOX_TXT}|sed -e 's/\\e[[0-9;]*[a-zA-Z]//g' -e 's/\\t//g' -e 's/\\n//g')
1847+ #Get Length
1848+ local BOX_TXT_CLN_LEN=${#BOX_TXT_CLN}
1849+ #Remember current cursor position
1850+ printf '\e[s'
1851+ #Get half of width of the actual text string (stripped of escape sequences
1852+ BOX_TXT_CLN_DIV=$((${#BOX_TXT_CLN}/2))
1853+ #Get half of width, starting from right margin - NOT specified width
1854+ BOX_MGN_DIV=$((${BOX_MGN//[ \\[a-zA-Z]/}/2))
1855+ #Subtract result of text string division from result of right margin division
1856+ #to get where text should start
1857+ BOX_TXT_CTR=$((${BOX_MGN_DIV}-${BOX_TXT_CLN_DIV}))
1858+ # Move cursor up 1/2 specified hght + 2
1859+ printf '\e['$(((${BOX_HGT}/2)+2))'A'
1860+ # Move cursor to BOX_TXT_CTR and type out text string
1861+ printf '\e['${BOX_TXT_CTR}'G'"${BOX_TXT}"''
1862+ #Return to original cursor position
1863+ printf '\e[u'
1864+ fi
1865+ #Unset any remaining ^BOX_ Vars
1866+ for var in $(set |grep -oE '^BOX.*=');do unset ${var:0:(-1)} unset $i 2>/dev/null;done
1867+}
1868+
1869+TagLine() {
1870+ local RVID=${FALSE}
1871+ local OPTIND o u c p P r
1872+ while getopts ":ucp:P:r" o; do
1873+ case "${o}" in
1874+ u) [[ -n ${TAG} ]] && printf "\n${BR}Error${RT}: Tagline Types are mutually exclusive\n" || local TAG="ubuntu"
1875+ ;;
1876+ c) [[ -n ${TAG} ]] && printf "\n${BR}Error${RT}: Tagline Types are mutually exclusive\n" || local TAG="canonical"
1877+ ;;
1878+ p) local PRETEXT="${OPTARG}"
1879+ ;;
1880+ P) local POSTTEXT="${OPTARG}"
1881+ ;;
1882+ r) local RVID="${TRUE}"
1883+ ;;
1884+ *) printf "\n${BR}Error${RT}: invalid option specified\n"
1885+ ;;
1886+ esac
1887+ done
1888+ shift $((OPTIND-1))
1889+ if [[ ${TAG} = canonical ]];then
1890+ [[ ${RVID} = ${TRUE} ]] && local COLOR='\e[1;38;5;89;48;5;255m' || local COLOR='\e[1;48;5;89m'
1891+ printf " ${COLOR}${PRETEXT} C a n o n i c a l \u25C9 \e[0m${COLOR}${POSTTEXT}\e[0m\n"
1892+ elif [[ ${TAG} = ubuntu ]];then
1893+ [[ ${RVID} = ${TRUE} ]] && local COLOR='\e[38;5;202;48;5;255m' || local COLOR='\e[1;48;5;202m'
1894+ printf " ${COLOR}${PRETEXT} U b u n t u \ue0ff \e[0m${COLOR}${POSTTEXT}\e[0m\n"
1895+ fi
1896+}
1897+
1898+FadeIn() { for i in {232..255};do printf '\r\e[38;5;'${i}'m'"${@}"'\e[0m';sleep .05;done; }
1899+FadeOut() { for i in {255..232};do printf '\r\e[38;5;'${i}'m'"${@}"'\e[0m';sleep .05;done; }
1900+
1901+FadeInO() { for i in $(seq 88 6 208);do printf '\r\e[38;5;'${i}'m'"${@}"'\e[0m';sleep .05;done; }
1902+FadeOutO() { for i in $(seq 208 -6 88);do printf '\r\e[38;5;'${i}'m'"${@}"'\e[0m';sleep .05;done; }
1903+########################################
1904+# Validation Functions
1905+########################################
1906+CheckUser() {
1907+ CheckUser_Usage(){ printf "\n${BY}${FUNCNAME%_*}${RT}\n\n\
1908+ \t${BU}${BY}Purpose${RT}\n\
1909+ \tChecks if user exists and returns an exit status\n\n\
1910+ \t${BY}Usage:${RT} ${FUNCNAME%_*}\n\n\
1911+ \t${BU}${BY}Exit Status${RT}\n\
1912+ \t0 = User exists\n\
1913+ \t1 = User does NOT exist\n\n" 1>&2; return; }
1914+ id ${1} > /dev/null 2>&1; echo $?;
1915+}
1916+CheckFile() {
1917+ CheckFile_Usage(){ printf "\n${BY}${FUNCNAME%_*}${RT}\n\n\
1918+ \t${BU}${BY}Purpose${RT}\n\
1919+ \tChecks if file exists and returns an exit status\n\n\
1920+ \t${BY}Usage:${RT} ${FUNCNAME%_*}\n\n\
1921+ \t${BU}${BY}Exit Status${RT}\n\
1922+ \t0 = File exists\n\
1923+ \t1 = File does NOT exist\n\n" 1>&2; return; }
1924+ [[ -f ${1} ]];echo $?;
1925+}
1926+CheckDir() {
1927+ CheckDir_Usage(){ printf "\n${BY}${FUNCNAME%_*}${RT}\n\n\
1928+ \t${BU}${BY}Purpose${RT}\n\
1929+ \tChecks if directory exists and returns an exit status\n\n\
1930+ \t${BY}Usage:${RT} ${FUNCNAME%_*}\n\n\
1931+ \t${BU}${BY}Exit Status${RT}\n\
1932+ \t0 = Directory exists\n\
1933+ \t1 = Directory does NOT exist\n\n" 1>&2; return; }
1934+ [[ -d ${1} ]];echo $?;
1935+}
1936+
1937+#Get primary interface and it's IP
1938+GetMgtInt() {
1939+ GetMgtInt_Usage(){ printf "\n${BY}${FUNCNAME%_*}${RT}\n\n\
1940+ \t${BU}${BY}Purpose${RT}\n\
1941+ \tReturns primary interface name and IP Address\n\n\
1942+ \t${BY}Usage:${RT} ${FUNCNAME%_*}\n\n\
1943+ \t${BU}${BY}Exit Status${RT}\n\
1944+ \t0 = Successfully determinied Primary Interace and IP Address\n\
1945+ \t1 = Could not determine Primary Interace and/or IP Address\n\n" 1>&2; return; }
1946+
1947+local MGTIF="$(route|awk '/default/{print $NF}')"
1948+local MGTIP="$(ifconfig ${MGTIF}|awk '/inet addr:/{gsub(/addr:/,"");print $2}')"
1949+[[ -z ${MGTIF} ]] && { printf "Error: Could not determine primary network interface." >&2; return 1; }
1950+[[ -z ${MGTIP} ]] && { printf "Error: Could not determine primary IP address." >&2; return 1; }
1951+[[ ! -z ${MGTIF} && ! -z ${MGTIP} ]] && { printf "${MGTIF}:${MGTIP}\n"; return 0; }
1952+}
1953+
1954+
1955+#function to check if variable is a number
1956+CheckNum() {
1957+CheckNum_Usage(){ printf "\nCheckNum: Validates that provided string is a number.\n\nReturn Code 0 = valid\nReturn Code 1 = invalid\n\nUsage: CheckNum <string>\n\n" 1>&2; }
1958+[[ $1 = '-h' || $1 = '--help' ]] && { CheckNum_Usage; return; }
1959+RegExNum='^[0-9]+$'
1960+[[ ${1} =~ $RegExNum ]] && return 0 || { printf "$FUNCNAME Error: \"${1}\" is not a number\n" &>/dev/null|tee -a ${FUNCLOG}; return 1; }
1961+}
1962+
1963+#function to check validity of IP address
1964+CheckIP() {
1965+CheckIP_Usage(){ printf "\nCheckIP: Validates that provided string is an IP Address.\n\nReturn Code 0 = valid\nReturn Code 1 = invalid\n\nUsage: CheckIP <string>\n\n" 1>&2; }
1966+[[ $1 = '-h' || $1 = '--help' ]] && { CheckIP_Usage; return; }
1967+local ip="${1}"
1968+[[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && { IFS=.; set $ip; for quad in 1 2 3 4; do $(eval [[ \$$quad -gt 255 ]] && return 1 || return 0);done; } || { printf "Error: ${ip} is an invalid IP address\n" >&2; return 1; }
1969+}
1970+
1971+#function to check to ensure that OB_NUM is divisible by four
1972+CheckDiv() {
1973+CheckDiv_Usage(){ printf "\nCheckDiv: Validates that variable \$OB_NUM is divisible by four.\n\nReturn Code 0 = valid\nReturn Code 1 = invalid\n\nUsage: CheckDiv <string>\n\n" 1>&2; }
1974+[[ $1 = '-h' || $1 = '--help' ]] && { CheckDiv_Usage; return; }
1975+[[ $(CheckNum ${1} -eq 0) ]] || { printf "$FUNCNAME Error:: \"${1}\" is not a number\n" &>/dev/null|tee -a ${FUNCLOG}; return 1; }
1976+[[ $((10#${1}%4)) -eq 0 ]] && return 0 || { printf "$FUNCNAME Error: ${1} is NOT divisble by 4.\n" &>/dev/null|tee -a ${FUNCLOG}; return 1; }
1977+}
1978+
1979+########################################
1980+# OrangeBox and Cannonical Functions
1981+########################################
1982+
1983+# Parameters for OrangeBox Units
1984+export OB_NUM=${HOSTNAME:9}
1985+export OB_BYTE1=${OB_NUM:0:1}
1986+export OB_BYTE2=${OB_NUM:1}
1987+[[ $(CheckNum ${OB_NUM};echo $?) -eq 0 ]] && export OB_PLUS1=$((10#${OB_NUM}+1)) || { printf "${BASH_SOURCE[@]##*/} warning: Cannot set parameter \$OB_PLUS1.\n" &>/dev/null|tee -a ${FUNCLOG}; }
1988+[[ $(CheckNum ${OB_NUM};echo $?) -eq 0 ]] && export OB_PLUS2=$((10#${OB_NUM}+2)) || { printf "${BASH_SOURCE[@]##*/} warning: Cannot set parameter \$OB_PLUS2.\n" &>/dev/null|tee -a ${FUNCLOG}; }
1989+[[ $(CheckNum ${OB_NUM};echo $?) -eq 0 ]] && export OB_PLUS3=$((10#${OB_NUM}+3)) || { printf "${BASH_SOURCE[@]##*/} warning: Cannot set parameter \$OB_PLUS3.\n" &>/dev/null|tee -a ${FUNCLOG}; }
1990+
1991+
1992+
1993+#OS Parameters
1994+if [[ -n $(which lsb_release) ]];then
1995+ export OB_OS_DISTRO=$(lsb_release -is)
1996+ export OB_OS_RELEASE=$(lsb_release -rs)
1997+ export OB_OS_CODENAME=$(lsb_release -cs)
1998+fi
1999+
2000+#Function to check if package is installed and get version
2001+IsInstalled() {
2002+IsInstalled_Usage(){ printf "\n${BY}${FUNCNAME%_*}${RT}\n\n\
2003+\t${BU}${BY}Purpose${RT}\n\
2004+\tChecks if a package is installed and returns an exit status\n\n\
2005+\t${BY}Usage:${RT} ${FUNCNAME%_*}\n\n\
2006+\t${BU}${BY}Exit Status${RT}\n\
2007+\t0 = Package Installed\n\
2008+\t1 = Package NOT intalled\n\n" 1>&2; return; }
2009+
2010+if [[ ${OB_OS_DISTRO} = Ubuntu ]];then
2011+ local mypkg="${1}"
2012+ local pkginstalled=$(dpkg-query -s ${mypkg} 2> /dev/null | grep -q ^"Status: install ok installed"$;echo $?)
2013+ [[ ${pkginstalled} -eq 0 ]] && { printf "$(dpkg-query -s ${mypkg} 2> /dev/null |awk '/Version: /{print $2}')\n";return 0; } || return 1
2014+fi
2015+}
2016+
2017+#Set OrangeBox directory variables based on versions
2018+[[ ! -z ${OB_OS_CODENAME} && ${OB_OS_CODENAME} = xenial ]] && export OB_INSTALL_DIR=/srv/obinstall
2019+[[ ! -z ${OB_OS_CODENAME} && ${OB_OS_CODENAME} = trusty ]] && export OB_INSTALL_DIR=/srv/obsetup
2020+[[ -z ${OB_INSTALL_DIR} ]] && { [[ ! -d /tmp/obtmp ]] && mkdir -p /tmp/obtmp; export OB_INSTALL_DIR=/tmp/obtmp; }
2021+export OB_DEMO_DIR=/srv/sademos
2022+
2023+#Check if any version of Juju is installed
2024+CheckJuJu() {
2025+CheckJuJu_Usage(){ printf "\nCheckJuJu: Checks if Juju is installed. If Juju is installed, continues to check if Juju 2.0 is installed.\n\n Sets variables \$JUJU_INSTALLED & \$JUJU_2_INSTALLED to either true or false\n\nUsage: CheckJuJu\n\n" 1>&2; }
2026+[[ $1 = '-h' || $1 = '--help' ]] && { CheckJuJu_Usage; return; }
2027+[[ $OB_OS_DISTRO = Ubuntu ]] && [[ $(dpkg -l |grep -iqo juju;echo $?) -eq 0 ]] && export JUJU_INSTALLED="$TRUE" || export JUJU_INSTALLED="$FALSE"
2028+[[ ${JUJU_INSTALLED} = ${TRUE} ]] && [[ $OB_OS_DISTRO = Ubuntu ]] && [[ $(dpkg -l |grep -iqE 'Juju-2.0';echo $?) -eq 0 ]] && export JUJU_2_INSTALLED="$TRUE" || export JUJU_2_INSTALLED="$FALSE"
2029+}
2030+
2031+#Check if any version of MaaS is installed
2032+CheckMaaS() {
2033+CheckJuJu_Usage(){ printf "\nCheckJuJu: Checks if MaaS is installed. If MaaS is installed, continues to check if MaaS 2.0 is installed.\n\n Sets variables \$MAAS_INSTALLED & \$MAAS_2_INSTALLED to either true or false\n\nUsage: CheckJuJu\n\n" 1>&2; }
2034+[[ $1 = '-h' || $1 = '--help' ]] && { CheckJuJu_Usage; return; }
2035+[[ $OB_OS_DISTRO = Ubuntu ]] &&[[ $(dpkg -l |grep -iqo maas;echo $?) -eq 0 ]] && export MAAS_INSTALLED="$TRUE" || export MAAS_INSTALLED="$FALSE"
2036+[[ ${MAAS_INSTALLED} = ${TRUE} ]] && [[ $OB_OS_DISTRO = Ubuntu ]] && [[ $(dpkg -l |grep -iqE 'maas.*2.0';echo $?) -eq 0 ]] && export MAAS_2_INSTALLED="$TRUE" || export MAAS_2_INSTALLED="$FALSE"
2037+}
2038+
2039+
2040+# Get Juju version/subversion (if Juju is installed)
2041+CheckJuJu
2042+[[ ${JUJU_INSTALLED} = ${TRUE} ]] && eval $(juju version|awk -F"-" '{print "export JUJU_VER="$1"\n" "export JUJU_SUBVER="$2"\n"}')
2043+
2044+
2045+#Specify location of cloud and cred yamls
2046+#Updated to reflect 2.0 JUJU_DATA location
2047+export MAAS_CLOUD_YAML="$HOME/.local/share/juju/maas-cloud.yaml"
2048+export MAAS_CRED_YAML="$HOME/.local/share/juju/maas-cred.yaml"
2049+export STACK_CLOUD_YAML="$HOME/.local/share/juju/stack-cloud.yaml"
2050+export STACK_CRED_YAML="$HOME/.local/share/juju/stack-cred.yaml"
2051+
2052+#Maas Parameters
2053+export MAAS_REGN_CONF='/etc/maas/regiond.conf'
2054+export MAAS_RACK_CONF='/etc/maas/rackd.conf'
2055+
2056+#Make sure ubuntu user can read the /etc/mass configuration files
2057+[[ -f ${MAAS_REGN_CONF} ]] && [[ ! -r ${MAAS_REGN_CONF} ]] && [[ $EUID -ne 0 ]] && sudo sh -c "chmod a+r ${MAAS_REGN_CONF}"
2058+[[ -f ${MAAS_RACK_CONF} ]] && [[ ! -r ${MAAS_RACK_CONF} ]] && [[ $EUID -ne 0 ]] && sudo sh -c "chmod a+r ${MAAS_RACK_CONF}"
2059+
2060+
2061+
2062+#Show parameters we've set that start with OB_, MAAS_, and JUJU_
2063+ShowParms() {
2064+ShowParms_Usage(){ printf "\nShowParms: Show parameters that start with OB_, MAAS_, and JUJU_.\n\nUsage: ShowParms\n\n" 1>&2; }
2065+[[ $1 = '-h' || $1 = '--help' ]] && { ShowParms; return; }
2066+set|grep -E '^OB_|^MAAS_|^JUJU_'
2067+}
2068+
2069+#Show functions available from functions file
2070+ShowFunctions() {
2071+ShowFunctions_Usage(){ printf "\nShowFunctions: Show functions sourced from this file.\n\nUsage: ShowFunctions\n\n" 1>&2; }
2072+[[ $1 = '-h' || $1 = '--help' ]] && { ShowFunctions; return; }
2073+ grep -E '^*(). {$' ${BASH_SOURCE}|sed 's/() {//g'
2074+}
2075+
2076+GetMaaSAPIKey() {
2077+GetMaaSAPIKey_Usage(){ printf "\nGetMaaSAPIKey: Exports a MaaS Region Controller\'s apikey as variable \$MAAS_API_KEY.\n\nUsage: GetMaaSAPIKey [OPTION]\n\n-p\t\tPrints the MaaS Region Controller\'s apikey\n\n" 1>&2; }
2078+[[ $1 = '-h' || $1 = '--help' ]] && { GetMaaSAPIKey_Usage; return; }
2079+[[ $EUID -ne 0 ]] && printf "\n${BW}${FUNCNAME} reqiures root access. ${BO}Invoking sudo${RT}....\n";export MAAS_API_KEY=$(sudo sh -c "maas-region apikey --username=admin") || export MAAS_API_KEY=$(maas-region apikey --username=admin)
2080+[[ ! -z ${MAAS_API_KEY} && ${1} = '-p' ]] && { printf "${MAAS_API_KEY}\n"; return 0; }
2081+[[ ! -z ${MAAS_API_KEY} ]] && return 0 || { printf "Error: ${MAAS_API_KEY} is null.\n"; return 1; }
2082+}
2083+
2084+GetMaaSRegnURL() {
2085+GetMaaSRegnURL_Usage(){ printf "\nGetMaaSRegnURL: Exports a MaaS Region Controller\'s URL as variable \$MAAS_REGN_URL.\n\nUsage: GetMaaSRegnURL [OPTION]\n\n-p\t\tPrints the MaaS Region Controller\'s URL\n\n" 1>&2; }
2086+[[ $1 = '-h' || $1 = '--help' ]] && { GetMaaSRegnURL_Usage; return; }
2087+[[ -f $MAAS_REGN_CONF ]] && export MAAS_REGN_URL=$(awk '/maas_url: /{print $2}' "${MAAS_REGN_CONF}") || { printf "Error: "${MAAS_REGN_CONF}" does not exist.\n" >&2; return 1; }
2088+[[ $(echo ${MAAS_REGN_URL}|grep -Eiq '^http.*maas$';echo $?) -eq 0 ]] || { printf "Error: ${MAAS_REGN_URL} does not appear valid.\n"; return 1; }
2089+[[ ! -z ${MAAS_REGN_URL} && ${1} = '-p' ]] && { printf "${MAAS_REGN_URL}\n"; return 0; }
2090+[[ ! -z ${MAAS_REGN_URL} ]] && return 0 || { printf "Error: ${MAAS_REGN_URL} is null.\n"; return 1; }
2091+}
2092+
2093+GetMaaSRegnIP() {
2094+GetMaaSRegnIP_Usage(){ printf "\nGetMaaSRegnIP: Exports a MaaS Region Controller\'s IP as variable \$MAAS_REGN_IP.\n\nUsage: GetMaaSRegnIP [OPTION]\n\n-p\t\tPrints the MaaS Region Controller\'s IP\n\n" 1>&2; }
2095+[[ $1 = '-h' || $1 = '--help' ]] && { GetMaaSRegnIP_Usage; return; }
2096+[[ -f $MAAS_REGN_CONF ]] && export MAAS_REGN_IP=$(awk -F'/' '/maas_url: /{print $3}' "${MAAS_REGN_CONF}") || { printf "Error: "${MAAS_REGN_CONF}" does not exist.\n" >&2; return 1; }
2097+[[ $(CheckIP "${MAAS_REGN_IP}") -eq 0 ]] || { printf "Error: ${MAAS_REGN_IP} does not appear valid.\n"; return 1; }
2098+[[ ! -z ${MAAS_REGN_IP} && ${1} = '-p' ]] && { printf "${MAAS_REGN_IP}\n"; return 0; }
2099+[[ ! -z ${MAAS_REGN_IP} ]] && return 0 || { printf "Error: ${MAAS_REGN_IP} is null.\n"; return 1; }
2100+}
2101+
2102+GetMaaSRackURL() {
2103+GetMaaSRackURL_Usage(){ printf "\nGetMaaSRackURL: Exports a MaaS Rack Controller\'s URL as variable \$MAAS_RACK_URL.\n\nUsage: GetMaaSRackURL [OPTION]\n\n-p\t\tPrints the MaaS Rack Controller\'s URL\n\n" 1>&2; }
2104+[[ $1 = '-h' || $1 = '--help' ]] && { GetMaaSRackURL_Usage; return; }
2105+[[ -f $MAAS_RACK_CONF ]] && export MAAS_RACK_URL=$(awk '/maas_url: /{print $2}' "${MAAS_RACK_CONF}") || { printf "Error: "${MAAS_RACK_CONF}" does not exist.\n" >&2; return 1; }
2106+[[ $(echo ${MAAS_RACK_URL}|grep -Eiq '^http.*maas$';echo $?) -eq 0 ]] || { printf "Error: ${MAAS_RACK_URL} does not appear valid.\n"; return 1; }
2107+[[ ! -z ${MAAS_RACK_URL} && ${1} = '-p' ]] && { printf "${MAAS_RACK_URL}\n"; return 0; }
2108+[[ ! -z ${MAAS_RACK_URL} ]] && return 0 || { printf "Error: ${MAAS_RACK_URL} is null.\n"; return 1; }
2109+}
2110+
2111+GetMaaSRackCUUID() {
2112+GetMaaSRackCUUID_Usage(){ printf "\nGetMaaSRackCUUID: Exports a MaaS Rack Controller\'s CUUID as variable \$MAAS_RACK_CUUID.\n\nUsage: GetMaaSRackCUUID [OPTION]\n\n-p\t\tPrints the MaaS Rack Controller\'s CUUID\n\n" 1>&2; }
2113+[[ $1 = '-h' || $1 = '--help' ]] && { GetMaaSRackCUUID_Usage; return; }
2114+[[ -f $MAAS_RACK_CONF ]] && export MAAS_RACK_CUUID=$(awk '/cluster_uuid: /{print $2}' "${MAAS_RACK_CONF}") || { printf "Error: "${MAAS_RACK_CONF}" does not exist.\n" >&2; return 1; }
2115+[[ ! -z ${MAAS_RACK_CUUID} && ${1} = '-p' ]] && { printf "${MAAS_RACK_CUUID}\n"; return 0; }
2116+[[ ! -z ${MAAS_RACK_CUUID} ]] && return 0 || { printf "Error: ${MAAS_RACK_CUUID} is null.\n"; return 1; }
2117+}
2118+
2119+#Get MaaS version and subversion from RESTful API (if MaaS 2.0 is installed)
2120+CheckMaaS
2121+if [[ ${MAAS_2_INSTALLED} = ${TRUE} ]];then
2122+ GetMaaSRegnIP
2123+ if [[ -n $(which jq) ]];then
2124+ export MAAS_VER=$(curl -s -H "Accept:application/json" -X GET http://${MAAS_REGN_IP}/MAAS/api/2.0/version/|jq -r .version)
2125+ export MAAS_SUBVER=$(curl -s -H "Accept:application/json" -X GET http://${MAAS_REGN_IP}//MAAS/api/2.0/version/|jq -r .subversion)
2126+
2127+ else
2128+ export MAAS_VER=$(curl -s -H "Accept:application/json" -X GET http://${MAAS_REGN_IP}//MAAS/api/2.0/version/|awk '/\"version\":/{gsub(/"|,/,"");print $4}')
2129+ export MAAS_SUBVER=$(curl -s -H "Accept:application/json" -X GET http://${MAAS_REGN_IP}//MAAS/api/2.0/version/|awk '/\"version\":/{gsub(/"|,/,"");print $2}')
2130+ fi
2131+fi
2132+#If running under Juju 2.0 with MaaS 2.0, set JUJU_DEV_FLAGS
2133+[[ $JUJU_VER =~ 2.0 && $MAAS_VER =~ 2.0 ]] && export JUJU_DEV_FEATURE_FLAGS=maas2
2134+# Also set same var for system env
2135+if [[ $EUID -eq 0 ]];then
2136+ [[ $OB_OS_DISTRO = Ubuntu ]] && [[ $(grep -iqo JUJU_DEV_FEATURE_FLAGS /etc/environment|echo $?) -eq 1 ]] && echo export JUJU_DEV_FEATURE_FLAGS=maas2 >> /etc/environment
2137+else
2138+ [[ $OB_OS_DISTRO = Ubuntu ]] && [[ $(grep -iqo JUJU_DEV_FEATURE_FLAGS /etc/environment|echo $?) -eq 1 ]] && { printf "\n${BW}${FUNCNAME} reqiures root access. ${BO}Invoking sudo${RT}....\n"; sudo sh -c "echo export JUJU_DEV_FEATURE_FLAGS=maas2 >> /etc/environment"; }
2139+
2140+fi
2141+
2142+MakeMaaSCloudYaml() {
2143+MakeMaaSCloudYaml_Usage(){ printf "\nMakeMaaSCloudYaml: Creates YAML file (${MAAS_CLOUD_YAML}) for maas cloud type to be consumed by juju add-cloud\n\nUsage: MakeMaaSCloudYaml\n\n" 1>&2; }
2144+[[ $1 = '-h' || $1 = '--help' ]] && { MakeMaaSCloudYaml_Usage; return; }
2145+GetMaaSRegnURL
2146+printf 'clouds:\n maas:\n type: maas\n auth-types: [oauth1]\n endpoint: '${MAAS_REGN_URL}'\n' > "${MAAS_CLOUD_YAML}"
2147+[[ $? -eq 0 ]] || { printf "Error creating "${MAAS_CLOUD_YAML}"\n"; return 1; }
2148+chmod a+r "${MAAS_CLOUD_YAML}"
2149+[[ $? -eq 0 ]] && return 0 || { printf "Error setting read permissions on "${MAAS_CLOUD_YAML}"\n"; return 1; }
2150+}
2151+
2152+MakeMaaSCredYaml() {
2153+MakeMaaSCredYaml_Usage(){ printf "\nMakeMaaSCredYaml: Creates YAML file (${MAAS_CRED_YAML}) for maas cloud type to be consumed by juju add-credential\n\nUsage: MakeMaaSCredYaml\n\n" 1>&2; }
2154+[[ $1 = '-h' || $1 = '--help' ]] && { MakeMaaSCredYaml_Usage; return; }
2155+GetMaaSAPIKey
2156+GetMaaSRegnIP
2157+[[ $(ip addr show dev br0 |grep -qo ${MAAS_REGN_IP}|echo $?) -eq 0 ]] || { printf "\n\e[1;31mThis function must be ran from MaaS Regional Controller.\e[0m\n";return 1; }
2158+printf 'credentials:\n maas:\n admin:\n auth-type: oauth1\n maas-oauth: '${MAAS_API_KEY}'\n' > "${MAAS_CRED_YAML}"
2159+[[ $? -eq 0 ]] || { printf "Error creating "${MAAS_CRED_YAML}"\n"; return 1; }
2160+chmod a+r "${MAAS_CRED_YAML}"
2161+[[ $? -eq 0 ]] && return 0 || { printf "Error setting read permissions on "${MAAS_CRED_YAML}"\n"; return 1; }
2162+}
2163+
2164+MakeStackCloudYaml() {
2165+MakeStackCloudYaml_Usage(){ printf "\nMakeStackCloudYaml: Creates a cloud YAML file (${STACK_CLOUD_YAML}) for Openstack cloud types to be consumed by juju add-cloud\n\nUsage: MakeStackCloudYaml [OPTIONS]\n\n\t-n\tCloud Name (Default: openstack)\n\t-r\tRegion Name (Default: local)\n\t-u\tOpenStack User Name (Default: admin)\n\t-a\tUser Authentication Type. Choose fron access-key or userpass (Default: userpass)\n\t-p\tUser Password (if selcted User Authentication Type = userpass)\n\t-k\tAccess-Key (if selcted User Authentication Type = access-key)\n\t-s\tSecret-Key (if selcted User Authentication Type = access-key)\n\t-t\tOpenstack Tennant Name \n\n" 1>&2; }
2166+
2167+[[ $1 = '-h' || $1 = '--help' ]] && { MakeStackCloudYaml_Usage; return; }
2168+ local OPTIND o a
2169+ while getopts ":n:a:r:e:h" o; do
2170+ case "${o}" in
2171+ [n]) STACK_NAME="echo ${OPTARG}||awk '{print tolower($0)}'"
2172+ ;;
2173+ [a]) STACK_AUTH_TYPE="echo ${OPTARG}||awk '{print tolower($0)}'"
2174+ ;;
2175+ [r]) STACK_REGION="echo ${OPTARG}||awk '{print tolower($0)}'"
2176+ ;;
2177+ [e]) STACK_ENDPOINT="echo ${OPTARG}||awk '{print tolower($0)}'"
2178+ ;;
2179+ [h]|*)
2180+ MakeStackCredYaml_Usage
2181+ return 0
2182+ ;;
2183+ esac
2184+ done
2185+
2186+#If they exist, use Openstack environment variables if available
2187+
2188+[[ -z ${STACK_AUTH_TYPE} ]] && STACK_AUTH_TYPE='userpass. access-key'
2189+[[ $(grep -qE 'userpass|access-key' <<< ${STACK_AUTH_TYPE};echo $?) -eq 1 ]] && { printf "Error: Invalid Authentication Type. Must be \"access-key\", \"userpass\" or a combination of both separated by commas\n"; return 1; }
2190+
2191+[[ ! -z ${OS_AUTH_URL} ]] && STACK_ENDPOINT=${OS_AUTH_URL}
2192+[[ -z ${STACK_ENDPOINT} ]] && { printf "Error: Endpoint is missing. Please enter the proper URL of your Keystone authentication endpoint\n"; return 1; }
2193+[[ ! -z ${OS_REGION_NAME} ]] && STACK_REGION=${OS_REGION_NAME}
2194+
2195+#If we got this far, make backup copy of existing cloud.yaml
2196+[[ -f ${STACK_CLOUD_YAML} ]] && { printf "Making backup of exsiting cloud.yaml file.\n"; mv ${STACK_CLOUD_YAML} ${STACK_CLOUD_YAML}.$TStamp; }
2197+
2198+#If function called while sudoing, ensure we create our openstack cloud yaml as the real user, not root
2199+if [[ $EUID -ne 0 ]];then
2200+ printf "clouds:\n ${STACK_NAME:-myopenstack}\n type: openstack\n auth-types:[${STACK_AUTH_TYPE}]\n region:\n ${STACK_REGION:-local}:\n endpoint:${STACK_ENDPOINT}\n" > "${STACK_CLOUD_YAML}"
2201+ [[ $? -eq 0 ]] || { printf "Error creating "${STACK_CLOUD_YAML}"\n"; return 1; }
2202+else
2203+ su $SUDO_USER -c "printf "clouds:\n ${STACK_NAME:-myopenstack}\n type: openstack\n auth-types:[${STACK_AUTH_TYPE}]\n region:\n ${STACK_REGION:-local}:\n endpoint:${STACK_ENDPOINT}\n" > "${STACK_CLOUD_YAML}""
2204+ [[ $? -eq 0 ]] || { printf "Error creating "${STACK_CLOUD_YAML}"\n"; return 1; }
2205+fi
2206+}
2207+
2208+MakeStackCredYaml() {
2209+
2210+MakeStackCredYaml_Usage(){ printf "\nMakeStackCredYaml: Creates a credentials YAML file (${STACK_CRED_YAML}) for Openstack cloud types to be consumed by juju add-credential\n\nUsage: MakeStackCredYaml [OPTIONS]\n\n\t-n\tCloud Name (Default: openstack)\n\t-r\tRegion Name (Default: local)\n\t-u\tOpenStack User Name (Default: admin)\n\t-a\tUser Authentication Type. Choose fron access-key or userpass (Default: userpass)\n\t-k\tAccess-Key (if Auth Type = access-key)\n\t-s\tSecret-Key (if Auth Type = access-key)\n\t-p\tUser Password (if Auth Type = userpass)\n\t-t\tOpenstack Tennant Name \n\n" 1>&2; }
2211+[[ $1 = '-h' || $1 = '--help' ]] && { MakeStackCredYaml_Usage; return; }
2212+ local OPTIND o a
2213+ while getopts ":n:r:u:a:p:k:s:t:h" o; do
2214+ case "${o}" in
2215+ [n]) STACK_CLOUD_NAME="echo ${OPTARG}||awk '{print tolower($0)}'"
2216+ ;;
2217+ [r]) STACK_REGION="echo ${OPTARG}||awk '{print tolower($0)}'"
2218+ ;;
2219+ [u]) STACK_USER="echo ${OPTARG}||awk '{print tolower($0)}'"
2220+ ;;
2221+ [a]) STACK_AUTH_TYPE="echo ${OPTARG}||awk '{print tolower($0)}'"
2222+ ;;
2223+ [p]) STACK_PASSWORD="${OPTARG}"
2224+ ;;
2225+ [k]) STACK_ACCESS_KEY="${OPTARG}"
2226+ ;;
2227+ [s]) STACK_SECRET_KEY="${OPTARG}"
2228+ ;;
2229+ [t]) STACK_TENNANT_NAME="echo ${OPTARG}||awk '{print tolower($0)}'"
2230+ ;;
2231+ [h]|*)
2232+ MakeStackCredYaml_Usage
2233+ return 0
2234+ ;;
2235+ esac
2236+ done
2237+
2238+#If they exist, use Openstack environment variables if available
2239+
2240+[[ ! -z ${OS_USERNAME} && ! -z ${OS_PASSWORD} && -z ${STACK_AUTH_TYPE} ]] && STACK_AUTH_TYPE=userpass
2241+[[ ! -z ${OS_ACCESS_KEY} && ! -z ${OS_SECRET_KEY} && -z ${STACK_AUTH_TYPE} ]] && STACK_AUTH_TYPE=access-key
2242+
2243+[[ ${STACK_AUTH_TYPE} != userpass || ${STACK_AUTH_TYPE} != access-key ]] && { printf "Error: Invalid Authentication Type. Must be \"access-key\" or \"userpass\"\n"; return 1; }
2244+
2245+[[ ! -z ${OS_REGION_NAME} ]] && STACK_REGION=${OS_REGION_NAME}
2246+[[ ! -z ${OS_USERNAME} ]] && STACK_USER=${OS_USERNAME}
2247+[[ ! -z ${OS_PASSWORD} ]] && STACK_USER=${OS_PASSWORD}
2248+[[ ! -z ${OS_ACCESS_KEY} ]] && STACK_ACCESS_KEY=${OS_ACCESS_KEY}
2249+[[ ! -z ${OS_SECRET_KEY} ]] && STACK_SECRET_KEY=${OS__SECRET_KEY}
2250+[[ ! -z ${OS_TENNANT_NAME} ]] && STACK_TENNANT_NAME=${OS_TENNANT_NAME}
2251+
2252+[[ -z ${STACK_TENNANT_NAME} ]] && { printf "Error: Missing Openstack Tennant Name\n"; return 1; }
2253+[[ -z ${STACK_PASSWORD} && ${STACK_AUTH_TYPE} = userpass ]] && { printf "Error: Missing Openstack Password for selected \"userpass\" authentication method\n"; return 1; }
2254+[[ -z ${STACK_ACCESS_KEY} && ${STACK_AUTH_TYPE} = access_key ]] && { printf "Error: Missing Openstack Access-Key for selected \"access-key\" authentication method\n"; return 1; }
2255+[[ -z ${STACK_SECRET_KEY} && ${STACK_AUTH_TYPE} = access_key ]] && { printf "Error: Missing Openstack Secret-Key for selected \"access-key\" authentication method\n"; return 1; }
2256+
2257+
2258+#If we got this far, make backup copy of existing credentials.yaml
2259+[[ -f ${STACK_CRED_YAML} ]] && { printf "Making backup of exsiting credentials.yaml file.\n"; mv ${STACK_CRED_YAML} ${STACK_CRED_YAML}.$TStamp; }
2260+
2261+#If function called while sudoing, ensure we create our openstack cred yaml as the real user, not root
2262+
2263+if [[ $EUID -ne 0 ]];then
2264+ printf "credentials:\n ${STACK_CLOUD_NAME:-openstack}:\n default-region: ${STACK_REGION:-local}\n ${STACK_USER:-admin}:\n" > "${STACK_CRED_YAML}"
2265+ if [[ ${STACK_AUTH_TYPE} = userpass ]];then
2266+ printf " auth-type: userpass\n password: ${STACK_PASSWORD}\n tennant-name: ${STACK_TENNANT_NAME}\n username: ${STACK_USER:-admin}\n" >> "${STACK_CRED_YAML}"
2267+ elif [[ ${STACK_AUTH_TYPE} = access-key ]];then
2268+ printf " auth-type: access-key\n access-key: ${STACK_ACCESS-KEY}\n secret-key: ${STACK_SECRET-KEY}\n tennant-name: ${STACK_TENNANT_NAME}\n" >> "${STACK_CRED_YAML}"
2269+ fi
2270+ [[ $? -eq 0 ]] || { printf "Error creating "${STACK_CRED_YAML}"\n"; return 1; }
2271+else
2272+ su $SUDO_USER -c "printf "credentials:\n ${STACK_CLOUD_NAME:-openstack}:\n default-region: ${STACK_REGION:-local}\n ${STACK_USER:-admin}:\n" > "${STACK_CRED_YAML}""
2273+ if [[ ${STACK_AUTH_TYPE} = userpass ]];then
2274+ su $SUDO_USER -c "printf " auth-type: userpass\n password: ${STACK_PASSWORD}\n tennant-name: ${STACK_TENNANT_NAME}\n username: ${STACK_USER:-admin}\n" >> "${STACK_CRED_YAML}""
2275+ elif [[ ${STACK_AUTH_TYPE} = access-key ]];then
2276+ su $SUDO_USER -c "printf " auth-type: access-key\n access-key: ${STACK_ACCESS-KEY}\n secret-key: ${STACK_SECRET-KEY}\n tennant-name: ${STACK_TENNANT_NAME}\n" >> "${STACK_CRED_YAML}""
2277+ fi
2278+ [[ $? -eq 0 ]] || { printf "Error creating "${STACK_CRED_YAML}"\n"; return 1; }
2279+fi
2280+}
2281+
2282+AddMaaSCloud() {
2283+AddMaasCloud_Usage(){ printf "\nAddMaasCloud: Adds MaaS cloud provider to Juju 2.0 using the YAML file ${MAAS_CLOUD_YAML}\n\nUsage: AddMaasCloud\n\n" 1>&2; }
2284+[[ $1 = '-h' || $1 = '--help' ]] && { AddMaasCloud_Usage; return; }
2285+#Ensure we run Juju commands as regular user
2286+[[ $EUID -ne 0 ]] && juju add-cloud maas ${MAAS_CLOUD_YAML} || su $SUDO_USER -c "juju add-cloud maas ${MAAS_CLOUD_YAML}"
2287+[[ $? -eq 0 ]] && return 0 || { printf "Error setting adding MaaS cloud type to Juju.\n"; return 1; }
2288+}
2289+
2290+AddMaaSCreds() {
2291+AddMaasCreds_Usage(){ printf "\nAddMaasCreds: Adds Credentials for MaaS cloud provider to Juju 2.0 using the YAML file ${MAAS_CRED_YAML}\n\nUsage: AddMaasCreds\n\n" 1>&2; }
2292+[[ $1 = '-h' || $1 = '--help' ]] && { AddMaasCreds_Usage; return; }
2293+#Ensure we run Juju commands as regular user
2294+[[ $EUID -ne 0 ]] && juju add-credential maas -f ${MAAS_CRED_YAML} --replace || su $SUDO_USER -c "juju add-credential maas -f ${MAAS_CRED_YAML} --replace"
2295+[[ $? -eq 0 ]] && return 0 || { printf "Error setting adding MaaS credentials to Juju.\n"; return 1; }
2296+}
2297+
2298+BootStrapMaaS() {
2299+AddMaaSCloud
2300+AddMaaSCreds
2301+BootStrapMaaS_Usage(){ printf "\nBootStrapMaaS: Bootstrap a juju controller for a MaaS cloud provider\n\nUsage: BootStrapMaaS <controller-name>\n\ncontroller-name\t\tAccepts controller-name as argument. If blank, default of "maas-controller" will be used.\n\n" 1>&2; }
2302+[[ $1 = '-h' || $1 = '--help' ]] && { BootStrapMaaS_Usage; return; }
2303+#Ensure we run Juju commands as regular user
2304+[[ -z $1 ]] && MAAS_CONTROLLER="maas-controller" || MAAS_CONTROLLER="${1}"
2305+[[ $EUID -ne 0 ]] && juju bootstrap ${MAAS_CONTROLLER} maas --to node00vm0ob${HOSTNAME:9}.maas --show-log --upload-tools || su $SUDO_USER -c "juju bootstrap ${MAAS_CONTROLLER} maas --to node00vm0ob${HOSTNAME:9}.maas --show-log --upload-tools"
2306+[[ $? -eq 0 ]] && { printf "Succcessfully bootstrapped Juju controller: ${MAAS_CONTROLLER} \n"; return 0; } || { printf "Error bootstrapping Juju controller:${MAAS_CONTROLLER}\n"; return 1; }
2307+}
2308+
2309+#Function to install OpenStack client Tools for testing
2310+InstallOStackTools() {
2311+InstallOStackTools_Usage(){ printf "\nInstallOStackTools: Installs client tools for testing an OpenStack Cloud.\n\nUsage: InstallOStackTools\n\n" 1>&2; }
2312+[[ $1 = '-h' || $1 = '--help' ]] && { InstallOStackTools_Usage; return; }
2313+printf "${BW}Installing ${BO}OpenStack Client Tools${RT}...\n";sleep 1
2314+[[ $EUID -ne 0 ]] && { printf "\n${BW}${FUNCNAME} reqiures root access. ${BO}Invoking sudo${RT}....\n"; sudo apt install -y python-novaclient python-keystoneclient python-glanceclient python-neutronclient; } || apt-get -y install python-novaclient python-keystoneclient python-glanceclient python-neutronclient
2315+[[ $? -eq 0 ]] && { printf "\n${BO}Succcessfully installed OpenStack Client Tools.${RT} \n"; return 0; } || { printf "\n${BR}Failed to install OpenStack Client Tools.${RT} \n"; return 1; }
2316+}
2317+
2318+#Function to register OrangeBox with Landscape Service
2319+OBRegLandscape() {
2320+OBRegLandscape_Usage(){ printf "\nOBRegLandscape: Registers an OrangeBox with Canonical\'s Landscape Service without user intervention.\n\nUsage: OBRegLandscape\n\nExit Code 0 = Success\nExit Code 1 = Failed\nExit Code 2 = Already registered\n\n" 1>&2; }
2321+[[ $1 = '-h' || $1 = '--help' ]] && { OBRegLandscape_Usage; return; }
2322+
2323+#Make sure we don't re-register the same box
2324+[[ -f /etc/landscape/client.conf ]] && { printf "\n${BO}${HOSTNAME}${BW} already appears to be registered with Landscape. To re-register or un-register ${BO}${HOSTNAME}${BW}, first run ${BY}UnRegLandscape${RT}\n"; return 2; }
2325+
2326+[[ ${HOSTNAME:0:9} != OrangeBox || -z ${OB_NUM} ]] && { printf "\n${BR}Hostname (${HOSTNAME}) does not appear to be correct for an OrangeBox.${RT} \n"; return 1; }
2327+[[ $EUID -ne 0 ]] && { printf "\n${BW}${FUNCNAME} reqiures root access. ${BO}Invoking sudo${RT}....\n"; [[ $(dpkg -l|grep -iq landscape-client;echo $?) -eq 0 ]] || { printf "\n${BW}Installing ${BO}Landscape Client${RT}...\n"; sudo sh -c "apt install -y landscape-client > /var/log/OBRegLandscape.log 2>&1"; sudo landscape-config -t "OrangeBox${OB_NUM}" -a cpe-sa -p " " --http-proxy="" --https-proxy="" --script-users="ALL" --silent; } } || { [[ $(dpkg -l|grep -iq landscape-client;echo $?) -eq 0 ]] || { printf "\n${BW}Installing ${BO}Landscape Client${RT}...\n"; apt install -y landscape-client > /var/log/OBRegLandscape.log 2>&1; landscape-config -t "OrangeBox${OB_NUM}" -a cpe-sa -p " " --http-proxy="" --https-proxy="" --script-users="ALL" --silent; } }
2328+[[ $? -eq 0 ]] && return 0 || return 1
2329+}
2330+
2331+#Function to unregister Landscape Service
2332+UnRegLandscape() {
2333+UnRegLandscape_Usage(){ printf "\nUnRegLandscape: Unregisters a system from current Landscape Service without user intervention.\n\nUsage: UnRegLandscape\n\nExit Code 0 = Success\nExit Code 1 = Failed\nExit Code 2 = Was Not registered\n\n" 1>&2; }
2334+[[ $1 = '-h' || $1 = '--help' ]] && { UnRegLandscape_Usage; return; }
2335+
2336+#Make sure we don't try unregister a machines that's never been registered
2337+[[ ! -f /etc/landscape/client.conf ]] && { printf "\n${BO}${HOSTNAME}${BW} does not appear to be registered with Landscape.${RT}\n"; return 2; }
2338+
2339+[[ $EUID -ne 0 ]] && { printf "\n${BW}${FUNCNAME} reqiures root access. ${BO}Invoking sudo${RT}....\n"; printf "\n${BW}Removing ${BO}Landscape Client${RT}...\n"; sudo sh -c "apt remove -y --purge landscape-client landscape-common > /var/log/UnRegLandscape.log 2>&1"; } || { printf "\n${BW}Removing ${BO}Landscape Client${RT}...\n"; apt remove -y --purge landscape-client landscape-common > /var/log/UnRegLandscape.log 2>&1; }
2340+[[ $? -eq 0 ]] && return 0 || return 1
2341+}
2342+
2343+#Function to print limited juju status output
2344+# Updated to match new juju status in beta9
2345+JStat () {
2346+if [[ ${JUJU_SUBVER//[ a-zA-Z]/} -le 8 ]];then
2347+ JStat_Usage () { printf "\nJStat: Prints a smaller subset of juju status output\n\nUsage: JStat [OPTION]\n\n\t-s\tPrint [Services] Block\n\t-r\tPrint [Relations] Block\n\t-u\tPrint [Units] Block\n\t-m\tPrint [Machines] Block\n\n" 1>&2; }
2348+ local OPTIND o a
2349+ while getopts ":SsRrUuMmHh" o; do
2350+ case "${o}" in
2351+ [Ss]) printf "\n${BW}Juju Limited Status: [${BO}Services${BW}]${RT}\n"
2352+ juju status | sed -n '/\[Services]/,/^$/{ s///;p}'
2353+ ;;
2354+ [Rr]) printf "\n${BW}Juju Limited Status: [${BO}Relations${BW}]${RT}\n"
2355+ juju status | sed -n '/\[Relations]/,/^$/{ s///;p}'
2356+ ;;
2357+ [Uu]) printf "\n${BW}Juju Limited Status: [${BO}Units${BW}]${RT}\n"
2358+ juju status | sed -n '/\[Units]/,/^$/{ s///;p}'
2359+ ;;
2360+ [Mm]) printf "\n${BW}Juju Limited Status: [${BO}Machines${BW}]${RT}\n"
2361+ juju status | sed -n '/\[Machines]/,/^$/{ s///;p}'
2362+ ;;
2363+ [Hh] | *)
2364+ JStat_Usage;
2365+ return 0
2366+ ;;
2367+ esac
2368+ done
2369+ [[ $OPTIND -eq 1 ]] && JStat_Usage
2370+ shift $((OPTIND-1))
2371+elif [[ ${JUJU_SUBVER//[ a-zA-Z]/} -ge 9 ]];then
2372+ JStat_Usage () { printf "\nJStat: Prints a smaller subset of juju status output\n\nUsage: JStat [OPTION]\n\n\t-a,-s\tPrint APP Block\n\t-r\tPrint RELATION Block\n\t-u\tPrint UNIT Block\n\t-m\tPrint MACHINE Block\n\n" 1>&2; }
2373+ local OPTIND o a
2374+ while getopts ":SsAaRrUuMmHh" o; do
2375+ case "${o}" in
2376+ [Aa]|[Ss]) printf "\n${BW}Juju Limited Status: ${BO}APP${RT}\n"
2377+ juju status | sed -n '/^APP/,/^$/p'
2378+ ;;
2379+ [Rr]) printf "\n${BW}Juju Limited Status: ${BO}RELATION${RT}\n"
2380+ juju status | sed -n '/^RELATION/,/^$/p'
2381+ ;;
2382+ [Uu]) printf "\n${BW}Juju Limited Status: ${BO}UNIT${RT}\n"
2383+ juju status | sed -n '/^UNIT/,/^$/p'
2384+ ;;
2385+ [Mm]) printf "\n${BW}Juju Limited Status: ${BO}MACHINE${RT}\n"
2386+ juju status | sed -n '/^MACHINE/,/^$/p'
2387+ ;;
2388+ [Hh] | *)
2389+ JStat_Usage;
2390+ return 0
2391+ ;;
2392+ esac
2393+ done
2394+ [[ $OPTIND -eq 1 ]] && JStat_Usage
2395+ shift $((OPTIND-1))
2396+fi
2397+}
2398+
2399+# TEMP_FUNCTION: This function is a work-around for current twistd3 permssion crash issue
2400+WaitForMaaSDir() {
2401+WaitForMaaSDir_Usage(){ printf "\nWaitForMaaSDir: Waits in background for arrival of /etc/mass then changes permissions to allow rw access.\n\nUsage: WaitForMaaSDir\n\n" 1>&2; }
2402+[[ $1 = '-h' || $1 = '--help' ]] && { WaitForMaaSDir_Usage; return; }
2403+if [[ $EUID -ne 0 ]];then
2404+ printf "\n${BW}${FUNCNAME} reqiures root access. ${BO}Invoking sudo${RT}....\n"
2405+ sudo sh -c "echo;while [ ! -f /etc/maas/rackd.conf ];do sleep 2;printf '\rWaiting for /etc/maas/rackd.conf to get created...';done;chmod -R a+rw /etc/maas/rackd.conf;printf '\n/etc/mass/rackd.conf was created and permissions have been changed\n' &"
2406+ sudo sh -c "echo;while [ ! -f /etc/maas/regiond.conf ];do sleep 2;printf '\rWaiting for /etc/maas/regiond.conf to get created...';done;chmod -R a+rw /etc/maas/regiond.conf;printf '\n/etc/mass/regiond.conf was created and permissions have been changed\n' &"
2407+else
2408+ echo;while [ ! -f /etc/maas/rackd.conf ];do sleep 2;printf '\rWaiting for /etc/maas/rackd.conf to get created...';done;chmod -R a+rw /etc/maas/rackd.conf;printf '\n/etc/mass/rackd.conf was created and permissions have been changed\n' &"
2409+ echo;while [ ! -f /etc/maas/regiond.conf ];do sleep 2;printf '\rWaiting for /etc/maas/regiond.conf to get created...';done;chmod -R a+rw /etc/maas/regiond.conf;printf '\n/etc/mass/regiond.conf was created and permissions have been changed\n' &"
2410+fi
2411+}
2412+
2413+# TEMP_FUNCTION: This function is a work-around for current twistd3 permssion crash issue
2414+WaitForMaaS() {
2415+WaitForMaaS_Usage(){ printf "\nWaitForMaaS: Waits in background for arrival of mass user and file then applies proper group membership.\n\nUsage: WaitForMaasDir\n\n" 1>&2; }
2416+[[ $1 = '-h' || $1 = '--help' ]] && { WaitForMaaS; return; }
2417+while [[ $(CheckDir /etc/maas) -eq 1 && $(CheckUser maas) -eq 1 && $(CheckFile /etc/maas/regiond.conf) -eq 1 && $(CheckFile /etc/maas/rackd.conf) -eq 1 ]];do echo "Waiting on MAAS User setup to complete"; sleep 5; done
2418+[[ ${EUID} -ne 0 ]] && sudo usermod -a -G maas root || usermod -a -G maas root
2419+[[ ${EUID} -ne 0 ]] && sudo usermod -a -G maas ubunutu || usermod -a -G maas ubuntu
2420+[[ ${EUID} -ne 0 ]] && sudo usermod -a -G libvirtd root || uusermod -a -G libvirtd root
2421+[[ ${EUID} -ne 0 ]] && sudo usermod -a -G libvirtd maas || usermod -a -G libvirtd maas
2422+}
2423+
2424+GetLPUsers() {
2425+GetLPUsers_Usage () { printf "\nGetLPUsers: Get List of LaunchPad Username\n\nUsage: GetLPUsers [OPTION]\n\n\t-g\tLaunchPad Group Name (Default ~cpe-sa)\n\t-p\tPrint list usernames to stdout\n\t-w\tWrite usernames to file \n\t-f\tFilename to store usernames (Default:${OB_INSTALL_DIR}/LP_USERS.list)\n\t-x\tDo not add sabdfl\n\t-h\tThis message\n\n" 1>&2; return 0; }
2426+unset LPU_ARR WRITE PRINT LPFILE LPDIR GROUP SABDFL
2427+LPFILE="${OB_INSTALL_DIR}/LP_USERS.list"
2428+LPDIR="${LPFILE%/*}"
2429+WRITE=${FALSE}
2430+PRINT=${FALSE}
2431+SABDFL=${TRUE}
2432+ local OPTIND o a
2433+ while getopts ":g:f:pwxh" o; do
2434+ case "${o}" in
2435+ [g]) GROUP="echo ${OPTARG}||awk '{print tolower($0)}'"
2436+ ;;
2437+ [f]) LPFILE="${OPTARG}"
2438+ ;;
2439+ [p]) PRINT="${TRUE}"
2440+ ;;
2441+ [w]) WRITE="${TRUE}"
2442+ ;;
2443+ [x]) SABDFL="${FALSE}"
2444+ ;;
2445+ [h]|*)
2446+ GetLPUsers_Usage
2447+ return 0
2448+ ;;
2449+ esac
2450+ done
2451+ [[ -z ${GROUP} ]] && GROUP='~cpe-sa'
2452+ [[ ${GROUP:0:1} = '~' ]] || GROUP='~'${GROUP}''
2453+ if [[ ${WRITE} = "${TRUE}" && ! -d ${LPDIR} ]];then
2454+ mkdir -p ${LPDIR}
2455+ [[ $? -eq 0 ]] || { printf "\nError: Could not create directory ${LPDIR} Will not write ${LPFILE}.\n"; WRITE="${FALSE}"; }
2456+ fi
2457+ if [[ ${WRITE} = "${TRUE}" && -f ${LPFILE} ]];then
2458+ mv ${LPFILE} ${LPFILE}.$TStamp
2459+ [[ $? -eq 0 ]] || { printf "\nError: Could not move existing ${LPFILE}. Will not write ${LPFILE}.\n"; WRITE="${FALSE}"; }
2460+ fi
2461+ [[ $OPTIND -eq 1 ]] && { GetLPUsers_Usage; return 0; }
2462+ shift $((OPTIND-1))
2463+ printf "\n${ROW}Attempting to fetch list of current ${GROUP} members ${RT}\n"
2464+ declare -a LPU_ARR=($([[ ${SABDFL} = ${TRUE} ]] && echo sabdfl;wget -qO- https://launchpad.net/${GROUP}/+members?active_batch=300 --no-check-certificate|awk '/sprite person/{gsub(/href="\/~|"/,"");print $2}'))
2465+ [[ ${#LPU_ARR[@]} -gt 1 ]] || { printf "\n${BR}ERROR: Pulled 0 users from${BW} ${GROUP}.${RT} Please double check group name\n\n"; unset LPU_ARR; return 1; }
2466+ [[ ! -z ${LPU_ARR} && ${WRITE} = "${TRUE}" ]] && { [[ ! -f ${LPFILE} ]] && touch ${LPFILE}; for i in ${LPU_ARR[@]};do echo "${i}" >> ${LPFILE};done; [[ -f ${LPFILE} ]] && WRC=0 || WRC=1; }
2467+ [[ ! -z ${LPU_ARR} && ${PRINT} = "${TRUE}" ]] && { printf "\n${BW}There are ${BO}${#LPU_ARR[@]} ${BW}Current Members in ${BO}${GROUP}${BW}:${RT}\n\n"; for i in ${LPU_ARR[@]};do echo "${i}";done; }
2468+ [[ ! -z ${LPU_ARR} ]] && [[ ${WRITE} = "${FALSE}" ]] && [[ ${PRINT} = "${FALSE}" ]] && { printf "\n${BW}There are ${BO}${#LPU_ARR[@]} ${BW}Current Members in ${BO}${GROUP}${BW}:${RT}\n\n"; for i in ${LPU_ARR[@]};do echo "${i}";done; }
2469+ unset LPU_ARR WRITE PRINT LPFILE LPDIR GROUP SABDFL
2470+ printf "\n"
2471+}
2472+
2473+#Function to get MikroTek Router Info
2474+GetMTRInfo() {
2475+GetMTRInfo_Usage(){ printf "\nGetMTRInfo: Function to get MikroTek Router Information.\n\nUsage: GetMTRInfon\n" 1>&2; }
2476+[[ $1 = '-h' || $1 = '--help' ]] && { GetMTRInfo_Usage; return; }
2477+ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no admin@172.27.21.254 \
2478+'/put "\n#START_SYSID\n";
2479+/system identity print;
2480+/put "\n#END_SYSID\n";
2481+/put "\n#START_SYSHEALTH\n";
2482+/system health print;
2483+/put "\n#END_SYSHEALTH\n";
2484+/put "\n#START_IPADDR\n";
2485+/ip address print;
2486+/put "\n#END_IPADDR\n";
2487+/put "\n#START_ROUTERINFO\n";
2488+/system routerboard print;
2489+/put "\n#END_ROUTERINFO\n";
2490+/put "\n#START_WIFINET\n";
2491+/interface wireless print;
2492+/put "\n#END_WIFINET\n";
2493+/put "\n#START_WIFIAUTH\n";
2494+/interface wireless security-profiles print;
2495+/put "\n#END_WIFIAUTH' > /tmp/routerinfo.txt
2496+}
2497+
2498+#Function to ping OB IP Addresses of br0 br1 from MikroTek Router IP Addresses
2499+MTRPingTest() {
2500+MTRPingTest_Usage(){ printf "\nMTRPingTest: Function to ping expected OB IP Addresses (br0,br1) from MikroTek IP Addresses.\n\nUsage: MTRPingTestn\n" 1>&2; }
2501+[[ $1 = '-h' || $1 = '--help' ]] && { MTRPingTest_Usage; return; }
2502+[[ -z ${OB_PLUS1} || -z ${OB_PLUS2} || -z ${OB_PLUS3} ]] && { printf "\nMTRPingTest: Cannot determine OrangeBox Number to set OrangeBox Networking\n"; return 1; }
2503+ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no admin@172.27.252.${OB_NUM} \
2504+'/put "\nPinging 172.27.${OB_NUM}.1 from 172.27.${OB_PLUS1}.254:\n";/ping 172.27.${OB_NUM}.1 count 2 src-address 172.27.${OB_PLUS1}.254;
2505+/put "\nPinging 172.27.${OB_NUM}.1 from 172.27.${OB_PLUS3}.254:\n";/ping 172.27.22.1 count 2 src-address 172.27.${OB_PLUS3}.254;
2506+/put "\nPinging 172.27.${OB_NUM}.1 from 172.27.252.${OB_NUM}:\n";/ping 172.27.${OB_NUM}.1 count 2 src-address 172.27.252.${OB_NUM};
2507+/put "\nPinging 172.27.${OB_PLUS2}.1 from 172.27.${OB_PLUS1}.254:\n";/ping 172.27.${OB_PLUS2}.1 count 2 src-address 172.27.${OB_PLUS1}.254;
2508+/put "\nPinging 172.27.${OB_PLUS2}.1 from 172.27.${OB_PLUS3}.254:\n";/ping 172.27.${OB_PLUS2}.1 count 2 src-address 172.27.${OB_PLUS3}.254;
2509+/put "\nPinging 172.27.${OB_PLUS2}.1 from 172.27.252.${OB_NUM}:\n";/ping 172.27.${OB_PLUS2}.1 count 2 src-address 172.27.252.${OB_NUM};'
2510+}
2511+
2512+PingWait() {
2513+unset psend precv
2514+local pinghost="${1}"
2515+setterm --cursor off
2516+while [ ${psend} -ne ${precv} ];do
2517+ Spinner "Waiting for ${pinghost} to arrive "
2518+ eval $(ping -w 1 -c 2 -q ${pinghost}|awk '/packets/{print "psend="$1"\nprecv="$4"\n"}')
2519+done
2520+printf "\rHost ${pinghost} has arrived! "
2521+setterm --cursor on
2522+printf "\n"
2523+unset psend precv
2524+}
2525+
2526+OB_OFF='
2527+┌──────────────────────────────────────────────┐
2528+│ ┌──────────────────────────────────────────┐ │
2529+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2530+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2531+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2532+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2533+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2534+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2535+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2536+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2537+│ └──────────────────────────────────────────┘ │
2538+└──────────────────────────────────────────────┘
2539+'
2540+OB_START_NODE1='
2541+┌──────────────────────────────────────────────┐
2542+│ ┌──────────────────────────────────────────┐ │
2543+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2544+│ │ │◎ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2545+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2546+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2547+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2548+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2549+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2550+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2551+│ └──────────────────────────────────────────┘ │
2552+└──────────────────────────────────────────────┘
2553+'
2554+OB_START_NODE2='
2555+┌──────────────────────────────────────────────┐
2556+│ ┌──────────────────────────────────────────┐ │
2557+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2558+│ │ │○ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2559+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2560+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2561+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2562+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2563+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2564+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2565+│ └──────────────────────────────────────────┘ │
2566+└──────────────────────────────────────────────┘
2567+'
2568+OB_START_NODE3='
2569+┌──────────────────────────────────────────────┐
2570+│ ┌──────────────────────────────────────────┐ │
2571+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2572+│ │ │○ ││○ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2573+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2574+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2575+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2576+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2577+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2578+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2579+│ └──────────────────────────────────────────┘ │
2580+└──────────────────────────────────────────────┘
2581+'
2582+OB_START_NODE4='
2583+┌──────────────────────────────────────────────┐
2584+│ ┌──────────────────────────────────────────┐ │
2585+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2586+│ │ │○ ││○ ││○ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2587+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2588+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2589+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2590+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2591+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2592+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2593+│ └──────────────────────────────────────────┘ │
2594+└──────────────────────────────────────────────┘
2595+'
2596+OB_START_NODE5='
2597+┌──────────────────────────────────────────────┐
2598+│ ┌──────────────────────────────────────────┐ │
2599+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2600+│ │ │○ ││○ ││○ ││○ ││◎ ││○ ││○ ││○ ││○ ││○ │ │ │
2601+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2602+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2603+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2604+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2605+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2606+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2607+│ └──────────────────────────────────────────┘ │
2608+└──────────────────────────────────────────────┘
2609+'
2610+OB_START_NODE6='
2611+┌──────────────────────────────────────────────┐
2612+│ ┌──────────────────────────────────────────┐ │
2613+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2614+│ │ │○ ││○ ││○ ││○ ││○ ││◎ ││○ ││○ ││○ ││○ │ │ │
2615+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2616+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2617+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2618+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2619+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2620+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2621+│ └──────────────────────────────────────────┘ │
2622+└──────────────────────────────────────────────┘
2623+'
2624+OB_START_NODE7='
2625+┌──────────────────────────────────────────────┐
2626+│ ┌──────────────────────────────────────────┐ │
2627+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2628+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││◎ ││○ ││○ ││○ │ │ │
2629+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2630+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2631+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2632+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2633+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2634+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2635+│ └──────────────────────────────────────────┘ │
2636+└──────────────────────────────────────────────┘
2637+'
2638+OB_START_NODE8='
2639+┌──────────────────────────────────────────────┐
2640+│ ┌──────────────────────────────────────────┐ │
2641+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2642+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││◎ ││○ ││○ │ │ │
2643+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2644+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2645+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2646+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2647+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2648+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2649+│ └──────────────────────────────────────────┘ │
2650+└──────────────────────────────────────────────┘
2651+'
2652+OB_START_NODE9='
2653+┌──────────────────────────────────────────────┐
2654+│ ┌──────────────────────────────────────────┐ │
2655+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2656+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││◎ ││○ │ │ │
2657+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2658+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2659+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2660+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2661+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2662+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2663+│ └──────────────────────────────────────────┘ │
2664+└──────────────────────────────────────────────┘
2665+'
2666+OB_START_NODE10='
2667+┌──────────────────────────────────────────────┐
2668+│ ┌──────────────────────────────────────────┐ │
2669+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2670+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││◎ │ │ │
2671+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2672+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2673+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2674+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2675+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2676+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2677+│ └──────────────────────────────────────────┘ │
2678+└──────────────────────────────────────────────┘
2679+'
2680+OB_START_ALL='
2681+┌──────────────────────────────────────────────┐
2682+│ ┌──────────────────────────────────────────┐ │
2683+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2684+│ │ │◎ ││◎ ││◎ ││◎ ││◎ ││◎ ││◎ ││◎ ││◎ ││◎ │ │ │
2685+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2686+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2687+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2688+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2689+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2690+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2691+│ └──────────────────────────────────────────┘ │
2692+└──────────────────────────────────────────────┘
2693+'
2694+OB_ON_NODE1='
2695+┌──────────────────────────────────────────────┐
2696+│ ┌──────────────────────────────────────────┐ │
2697+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2698+│ │ │◉ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2699+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2700+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2701+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2702+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2703+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2704+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2705+│ └──────────────────────────────────────────┘ │
2706+└──────────────────────────────────────────────┘
2707+'
2708+OB_ON_NODE2='
2709+┌──────────────────────────────────────────────┐
2710+│ ┌──────────────────────────────────────────┐ │
2711+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2712+│ │ │○ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2713+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2714+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2715+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2716+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2717+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2718+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2719+│ └──────────────────────────────────────────┘ │
2720+└──────────────────────────────────────────────┘
2721+'
2722+OB_ON_NODE3='
2723+┌──────────────────────────────────────────────┐
2724+│ ┌──────────────────────────────────────────┐ │
2725+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2726+│ │ │○ ││○ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2727+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2728+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2729+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2730+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2731+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2732+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2733+│ └──────────────────────────────────────────┘ │
2734+└──────────────────────────────────────────────┘
2735+'
2736+OB_ON_NODE4='
2737+┌──────────────────────────────────────────────┐
2738+│ ┌──────────────────────────────────────────┐ │
2739+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2740+│ │ │○ ││○ ││○ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2741+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2742+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2743+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2744+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2745+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2746+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2747+│ └──────────────────────────────────────────┘ │
2748+└──────────────────────────────────────────────┘
2749+'
2750+OB_ON_NODE5='
2751+┌──────────────────────────────────────────────┐
2752+│ ┌──────────────────────────────────────────┐ │
2753+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2754+│ │ │○ ││○ ││○ ││○ ││◉ ││○ ││○ ││○ ││○ ││○ │ │ │
2755+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2756+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2757+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2758+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2759+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2760+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2761+│ └──────────────────────────────────────────┘ │
2762+└──────────────────────────────────────────────┘
2763+'
2764+OB_ON_NODE6='
2765+┌──────────────────────────────────────────────┐
2766+│ ┌──────────────────────────────────────────┐ │
2767+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2768+│ │ │○ ││○ ││○ ││○ ││○ ││◉ ││○ ││○ ││○ ││○ │ │ │
2769+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2770+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2771+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2772+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2773+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2774+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2775+│ └──────────────────────────────────────────┘ │
2776+└──────────────────────────────────────────────┘
2777+'
2778+OB_ON_NODE7='
2779+┌──────────────────────────────────────────────┐
2780+│ ┌──────────────────────────────────────────┐ │
2781+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2782+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││◉ ││○ ││○ ││○ │ │ │
2783+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2784+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2785+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2786+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2787+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2788+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2789+│ └──────────────────────────────────────────┘ │
2790+└──────────────────────────────────────────────┘
2791+'
2792+OB_ON_NODE8='
2793+┌──────────────────────────────────────────────┐
2794+│ ┌──────────────────────────────────────────┐ │
2795+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2796+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││◉ ││○ ││○ │ │ │
2797+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2798+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2799+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2800+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2801+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2802+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2803+│ └──────────────────────────────────────────┘ │
2804+└──────────────────────────────────────────────┘
2805+'
2806+OB_ON_NODE9='
2807+┌──────────────────────────────────────────────┐
2808+│ ┌──────────────────────────────────────────┐ │
2809+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2810+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││◉ ││○ │ │ │
2811+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2812+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2813+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2814+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2815+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2816+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2817+│ └──────────────────────────────────────────┘ │
2818+└──────────────────────────────────────────────┘
2819+'
2820+OB_ON_NODE10='
2821+┌──────────────────────────────────────────────┐
2822+│ ┌──────────────────────────────────────────┐ │
2823+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2824+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││◉ │ │ │
2825+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2826+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2827+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2828+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2829+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2830+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2831+│ └──────────────────────────────────────────┘ │
2832+└──────────────────────────────────────────────┘
2833+'
2834+OB_START_NODE1_2='
2835+┌──────────────────────────────────────────────┐
2836+│ ┌──────────────────────────────────────────┐ │
2837+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2838+│ │ │◉ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2839+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2840+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2841+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2842+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2843+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2844+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2845+│ └──────────────────────────────────────────┘ │
2846+└──────────────────────────────────────────────┘
2847+'
2848+OB_START_NODE1_3='
2849+┌──────────────────────────────────────────────┐
2850+│ ┌──────────────────────────────────────────┐ │
2851+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2852+│ │ │◉ ││◉ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2853+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2854+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2855+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2856+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2857+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2858+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2859+│ └──────────────────────────────────────────┘ │
2860+└──────────────────────────────────────────────┘
2861+'
2862+OB_START_NODE1_4='
2863+┌──────────────────────────────────────────────┐
2864+│ ┌──────────────────────────────────────────┐ │
2865+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2866+│ │ │◉ ││◉ ││◉ ││◎ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2867+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2868+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2869+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2870+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2871+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2872+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2873+│ └──────────────────────────────────────────┘ │
2874+└──────────────────────────────────────────────┘
2875+'
2876+OB_START_NODE1_5='
2877+┌──────────────────────────────────────────────┐
2878+│ ┌──────────────────────────────────────────┐ │
2879+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2880+│ │ │◉ ││◉ ││◉ ││◉ ││◎ ││○ ││○ ││○ ││○ ││○ │ │ │
2881+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2882+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2883+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2884+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2885+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2886+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2887+│ └──────────────────────────────────────────┘ │
2888+└──────────────────────────────────────────────┘
2889+'
2890+OB_START_NODE1_6='
2891+┌──────────────────────────────────────────────┐
2892+│ ┌──────────────────────────────────────────┐ │
2893+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2894+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◎ ││○ ││○ ││○ ││○ │ │ │
2895+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2896+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2897+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2898+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2899+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2900+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2901+│ └──────────────────────────────────────────┘ │
2902+└──────────────────────────────────────────────┘
2903+'
2904+OB_START_NODE1_7='
2905+┌──────────────────────────────────────────────┐
2906+│ ┌──────────────────────────────────────────┐ │
2907+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2908+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◎ ││○ ││○ ││○ │ │ │
2909+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2910+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2911+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2912+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2913+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2914+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2915+│ └──────────────────────────────────────────┘ │
2916+└──────────────────────────────────────────────┘
2917+'
2918+OB_START_NODE1_8='
2919+┌──────────────────────────────────────────────┐
2920+│ ┌──────────────────────────────────────────┐ │
2921+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2922+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◎ ││○ ││○ │ │ │
2923+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2924+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2925+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2926+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2927+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2928+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2929+│ └──────────────────────────────────────────┘ │
2930+└──────────────────────────────────────────────┘
2931+'◎
2932+OB_START_NODE1_9='
2933+┌──────────────────────────────────────────────┐
2934+│ ┌──────────────────────────────────────────┐ │
2935+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2936+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◎ ││○ │ │ │
2937+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2938+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2939+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2940+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2941+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2942+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2943+│ └──────────────────────────────────────────┘ │
2944+└──────────────────────────────────────────────┘
2945+'
2946+OB_START_NODE1_10='
2947+┌──────────────────────────────────────────────┐
2948+│ ┌──────────────────────────────────────────┐ │
2949+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2950+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◎ │ │ │
2951+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2952+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2953+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2954+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2955+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2956+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2957+│ └──────────────────────────────────────────┘ │
2958+└──────────────────────────────────────────────┘
2959+'
2960+OB_ON_NODE1_2='
2961+┌──────────────────────────────────────────────┐
2962+│ ┌──────────────────────────────────────────┐ │
2963+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2964+│ │ │◉ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2965+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2966+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2967+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2968+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2969+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2970+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2971+│ └──────────────────────────────────────────┘ │
2972+└──────────────────────────────────────────────┘
2973+'
2974+OB_ON_NODE1_3='
2975+┌──────────────────────────────────────────────┐
2976+│ ┌──────────────────────────────────────────┐ │
2977+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2978+│ │ │◉ ││◉ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2979+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2980+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2981+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2982+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2983+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2984+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2985+│ └──────────────────────────────────────────┘ │
2986+└──────────────────────────────────────────────┘
2987+'
2988+OB_ON_NODE1_4='
2989+┌──────────────────────────────────────────────┐
2990+│ ┌──────────────────────────────────────────┐ │
2991+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
2992+│ │ │◉ ││◉ ││◉ ││◉ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2993+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
2994+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2995+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2996+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2997+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
2998+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
2999+│ └──────────────────────────────────────────┘ │
3000+└──────────────────────────────────────────────┘
3001+'
3002+OB_ON_NODE1_5='
3003+┌──────────────────────────────────────────────┐
3004+│ ┌──────────────────────────────────────────┐ │
3005+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
3006+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││○ ││○ ││○ ││○ ││○ │ │ │
3007+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
3008+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3009+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3010+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3011+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3012+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
3013+│ └──────────────────────────────────────────┘ │
3014+└──────────────────────────────────────────────┘
3015+'
3016+OB_ON_NODE1_6='
3017+┌──────────────────────────────────────────────┐
3018+│ ┌──────────────────────────────────────────┐ │
3019+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
3020+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││○ ││○ ││○ ││○ │ │ │
3021+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
3022+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3023+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3024+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3025+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3026+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
3027+│ └──────────────────────────────────────────┘ │
3028+└──────────────────────────────────────────────┘
3029+'
3030+OB_ON_NODE1_7='
3031+┌──────────────────────────────────────────────┐
3032+│ ┌──────────────────────────────────────────┐ │
3033+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
3034+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││○ ││○ ││○ │ │ │
3035+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
3036+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3037+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3038+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3039+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3040+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
3041+│ └──────────────────────────────────────────┘ │
3042+└──────────────────────────────────────────────┘
3043+'
3044+OB_ON_NODE1_8='
3045+┌──────────────────────────────────────────────┐
3046+│ ┌──────────────────────────────────────────┐ │
3047+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
3048+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││○ ││○ │ │ │
3049+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
3050+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3051+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3052+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3053+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3054+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
3055+│ └──────────────────────────────────────────┘ │
3056+└──────────────────────────────────────────────┘
3057+'
3058+OB_ON_NODE1_9='
3059+┌──────────────────────────────────────────────┐
3060+│ ┌──────────────────────────────────────────┐ │
3061+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
3062+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││○ │ │ │
3063+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
3064+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3065+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3066+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3067+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3068+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
3069+│ └──────────────────────────────────────────┘ │
3070+└──────────────────────────────────────────────┘
3071+'
3072+
3073+OB_ON_ALL='
3074+┌──────────────────────────────────────────────┐
3075+│ ┌──────────────────────────────────────────┐ │
3076+│ │ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ │ │
3077+│ │ │◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ ││◉ │ │ │
3078+│ │ │○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ ││○ │ │ │
3079+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3080+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3081+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3082+│ │ │ ││ ││ ││ ││ ││ ││ ││ ││ ││ │ │ │
3083+│ │ └──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘└──┘ │ │
3084+│ └──────────────────────────────────────────┘ │
3085+└──────────────────────────────────────────────┘
3086+'
3087+ShowLights() {
3088+clear;printf "${OB_OFF}";sleep .5;clear;printf "${OB_START_ALL}";sleep .5
3089+for i in {1..10};do clear;eval printf \"\$OB_START_NODE${i}\";sleep .25;clear;eval printf \"\$OB_ON_NODE${i}\"; sleep .25; done
3090+for i in {10..1};do clear;eval printf \"\$OB_ON_NODE${i}\";sleep .25;clear;eval printf \"\$OB_START_NODE${i}\";sleep .25;done
3091+clear;printf "${OB_ON_NODE1}";sleep .25
3092+for i in {2..9};do clear; eval printf \"\$OB_START_NODE1_${i}\";sleep .25;clear;eval printf \"\$OB_ON_NODE1_${i}\"; sleep .25; done
3093+clear;printf "${OB_START_NODE1_10}";sleep .25;clear;printf "${OB_ON_ALL}";sleep .15;clear;printf "${OB_START_NODE1_10}";sleep .25;
3094+for i in {9..2};do clear; eval printf \"\$OB_START_NODE1_${i}\";sleep .25;clear;eval printf \"\$OB_ON_NODE1_${i}\"; sleep .25; done
3095+clear;printf "${OB_ON_ALL}";sleep .5;clear;printf "${OB_START_ALL}";sleep .15;clear;printf "${OB_OFF}"
3096+clear;printf "${OB_START_ALL}";sleep .5;clear;printf "${OB_OFF}";sleep .15
3097+clear;printf "${OB_START_ALL}";sleep .5;clear;printf "${OB_OFF}";sleep .15
3098+clear;printf "${OB_START_ALL}";clear;printf "${OB_OFF}";sleep .15
3099+sleep 2
3100+}

Subscribers

People subscribed via source and target branches

to all changes: