aboutsummaryrefslogtreecommitdiffstats
path: root/hived
diff options
context:
space:
mode:
authorterminaldweller <thabogre@gmail.com>2021-05-14 18:14:50 +0000
committerterminaldweller <thabogre@gmail.com>2021-05-14 18:14:50 +0000
commit6e528248414e330c9e25e81596ab47b8b8a5b701 (patch)
treee1aa41a7f3198eeac187e6177ec7d4a33db229d3 /hived
downloadscripts-master.tar.gz
scripts-master.zip
first commitmaster
Diffstat (limited to '')
-rwxr-xr-xhived704
-rw-r--r--hived.desktop5
-rwxr-xr-xhivedup.sh4
3 files changed, 713 insertions, 0 deletions
diff --git a/hived b/hived
new file mode 100755
index 0000000..d6346bc
--- /dev/null
+++ b/hived
@@ -0,0 +1,704 @@
+#!/usr/bin/python3
+
+import argparse
+import hashlib
+import hmac
+import json
+import requests
+import os
+import sys
+# import csv
+import socket
+import time
+import threading
+import atexit
+import signal
+# import selectors
+# from tempfile import TemporaryFile
+from abc import ABCMeta, abstractmethod
+from io import TextIOWrapper, BytesIO
+# import subprocess
+from _thread import *
+import threading
+sys.path.insert(0, "/home/bloodstalker/extra/seer/")
+shut_up = sys.stdout
+seriously = sys.stderr
+sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding)
+sys.stderr = TextIOWrapper(BytesIO(), sys.stdout.encoding)
+# from seer import launch_ais
+sys.stdout = shut_up
+sys.stderr = seriously
+
+api_url_base = "https://api.coinmarketcap.com/v1/ticker/"
+assets_file = "/home/bloodstalker/scripts/assets.json"
+api_url_base_shapeshift = "https://shapeshift.io/getcoins"
+test_url = "https://api.coinmarketcap.com/v1/ticker/?start=0&limit=300"
+cryptocompare_price_url = "https://min-api.cryptocompare.com/data/price?"
+
+# argument parser calls sys.exit() on exception, we don't want that.
+
+
+class ArgumentParseError(Exception):
+ pass
+
+
+class ArgumentParserWithoutExit(argparse.ArgumentParser):
+ def error(self, message):
+ raise ArgumentParseError(message)
+
+
+class Argparser(object):
+ def __init__(self):
+ self.parser = ArgumentParserWithoutExit()
+ self.parser.add_argument(
+ "--name", type=str, help="price of the chose crypto")
+ self.parser.add_argument(
+ "--worth", type=str, help="single asset worth")
+ self.parser.add_argument("--xx", type=str, nargs=2, help="convert")
+ self.parser.add_argument("--xxv", type=float, help="xx multiplier")
+ self.parser.add_argument(
+ "--gen", type=str, nargs=2, help="general option")
+ self.parser.add_argument("--cap", type=str, help="market cap")
+ self.parser.add_argument("--rank", type=str, help="market cap rank")
+ self.parser.add_argument(
+ "--total", action="store_true", help="total", default=False)
+ self.parser.add_argument(
+ "--ava", type=str, help="is currency available on changelly")
+ self.parser.add_argument(
+ "--avass", type=str, help="is currency available on shapeshift")
+ self.parser.add_argument("--cglistall", action="store_true",
+ help="list all currencies available on changelly", default=False)
+ self.parser.add_argument(
+ "--test", action="store_true", help="test switch", default=False)
+ self.parser.add_argument(
+ "--watchlist", type=str, nargs="+", help="watch list")
+ self.parser.add_argument(
+ "--ss", type=str, nargs="+", help="watchlist on shapeshift")
+ self.parser.add_argument("--dy", type=int, help="lazy")
+ self.parser.add_argument(
+ "--demon", action="store_true", help="daemon mode", default=False)
+ self.parser.add_argument(
+ "--al1", action="store_true", help="alert1", default=False)
+ self.parser.add_argument(
+ "--al2", action="store_true", help="alert2", default=False)
+ self.parser.add_argument(
+ "--al3", action="store_true", help="alert3", default=False)
+ self.parser.add_argument(
+ "--al4", action="store_true", help="alert4", default=False)
+ self.parser.add_argument(
+ "--al5", action="store_true", help="alert5", default=False)
+ self.parser.add_argument(
+ "--dbg", action="store_true", help="debug", default=False)
+ self.parser.add_argument(
+ "--alive", action="store_true", help="is hived up", default=False)
+ self.parser.add_argument(
+ "--tg", action="store_true", help="tg", default=False)
+ self.parser.add_argument(
+ "--mahsaread", action="store_true", help="mark as read", default=False)
+ self.parser.add_argument(
+ "--ai", action="store_true", help="which ai to launch", default=False)
+
+ def parse(self, argv):
+ self.args, self.rest = self.parser.parse_known_args(argv)
+
+
+class Colors:
+ purple = '\033[95m'
+ blue = '\033[94m'
+ green = '\033[92m'
+ yellow = '\033[93m'
+ red = '\033[91m'
+ grey = '\033[1;37m'
+ darkgrey = '\033[1;30m'
+ cyan = '\033[1;36m'
+ ENDC = '\033[0m'
+ BOLD = '\033[1m'
+ UNDERLINE = '\033[4m'
+
+
+def get_info_w_name(api_url, name):
+ cc_key = json.load(
+ open("/home/bloodstalker/scripts/cryptocompare_key.json"))["key"]
+ #response = requests.get(cryptocompare_price_url + "fsym=" + name + "&" + "tsyms=USD&" + "api_key=" + cc_key)
+ response = requests.get(cryptocompare_price_url +
+ "fsym=" + name + "&" + "tsyms=USD&")
+ if response.status_code == 200:
+ return json.loads(response.content.decode('utf-8'))
+ else:
+ return None
+
+
+def changelly():
+ API_URL = 'https://api.changelly.com'
+ API_KEY = '1a17d70c8b624a398c3ec1e4dbffbaa5'
+ API_SECRET = json.load(
+ open("/home/bloodstalker/scripts/changelly_api_secret.json"))["key"]
+ message = {
+ 'jsonrpc': '2.0',
+ 'id': 1,
+ 'method': 'getCurrencies',
+ 'params': []
+ }
+
+ serialized_data = json.dumps(message)
+ sign = hmac.new(API_SECRET.encode('utf-8'),
+ serialized_data.encode('utf-8'), hashlib.sha512).hexdigest()
+ headers = {'api-key': API_KEY, 'sign': sign,
+ 'Content-type': 'application/json'}
+ response = requests.post(API_URL, headers=headers, data=serialized_data)
+ if response.status_code == 200:
+ return (response.json()['result'])
+ else:
+ return None
+
+
+def vocalize(sound):
+ # for whatever weird reason this causes a hang
+ # subprocess.call([os.path.expanduser("~")+"/scripts/voice.sh", sound])
+ pass
+
+
+def trim(num, dig):
+ from math import log10, floor, ceil
+ power = ceil(log10(num))
+ power = dig - power
+ result = int(num * pow(10, power))
+ count = ceil(log10(result))
+ digits = list(str(result))
+ if power > ceil(log10(num)):
+ for i in range(0, abs(power)-count):
+ digits.insert(0, "0")
+ digits.insert(ceil(log10(num)) if log10(num) > 0 else 0, ".")
+ elif power < 0:
+ for i in range(0, abs(power)):
+ digits.insert(len(digits), "0")
+ else:
+ digits.insert(-abs(power) + count, ".")
+ return("".join(digits))
+
+
+def highpercentdump(number):
+ dic_7d = {}
+ dic_7d_sorted = {}
+ list_7d_key = []
+ list_7d_value = []
+
+ dic_24h = {}
+ dic_24h_sorted = {}
+ list_24h_key = []
+ list_24h_value = []
+
+ dic_1h = {}
+ dic_1h_sorted = {}
+ list_1h_key = []
+ list_1h_value = []
+
+ res = get_info_w_name(test_url, "")
+
+ for i in range(0, 300):
+ price = res[i]["percent_change_7d"]
+ if price == None:
+ price = 0
+ dic_7d[res[i]["name"]] = float(price)
+ for key, value in sorted(dic_7d.items(), key=lambda kv: (kv[1], kv[0])):
+ dic_7d_sorted[key] = value
+ for k, v in dic_7d_sorted.items():
+ list_7d_key.append(k)
+ list_7d_value.append(v)
+
+ for i in range(0, 300):
+ price = res[i]["percent_change_24h"]
+ if price == None:
+ price = 0
+ dic_24h[res[i]["name"]] = float(price)
+ for key, value in sorted(dic_24h.items(), key=lambda kv: (kv[1], kv[0])):
+ dic_24h_sorted[key] = value
+ for k, v in dic_24h_sorted.items():
+ list_24h_key.append(k)
+ list_24h_value.append(v)
+
+ for i in range(0, 300):
+ price = res[i]["percent_change_1h"]
+ if price == None:
+ price = 0
+ dic_1h[res[i]["name"]] = float(price)
+ for key, value in sorted(dic_1h.items(), key=lambda kv: (kv[1], kv[0])):
+ dic_1h_sorted[key] = value
+ for k, v in dic_1h_sorted.items():
+ list_1h_key.append(k)
+ list_1h_value.append(v)
+
+ col_width_1 = max(len(word) for word in list_7d_key) + \
+ max(len(repr(word)) for word in list_7d_value) + 2
+ col_width_2 = max(len(word) for word in list_7d_key) + \
+ max(len(repr(word)) for word in list_7d_value) + 2
+ col_width_3 = max(len(word) for word in list_7d_key) + \
+ max(len(repr(word)) for word in list_7d_value) + 2
+ col_width = max(col_width_1, col_width_2, col_width_3, 40)
+ print(("\t" + Colors.green + Colors.BOLD +
+ "7d:").ljust(col_width + 10), end="")
+ print("24h:".ljust(col_width), end="")
+ print(("1h:" + Colors.ENDC).ljust(col_width))
+ for i in range(300-number, 300):
+ print((Colors.red + Colors.BOLD + repr(300-i) +
+ Colors.ENDC).ljust(21), end="")
+ print((Colors.blue+list_7d_key[i]+Colors.ENDC+":"+Colors.cyan+Colors.BOLD+repr(
+ list_7d_value[i])+Colors.ENDC).ljust(col_width + 24), end="")
+ print((Colors.blue+list_24h_key[i]+Colors.ENDC+":"+Colors.cyan+Colors.BOLD+repr(
+ list_24h_value[i])+Colors.ENDC).ljust(col_width+24), end="")
+ print((Colors.blue+list_1h_key[i]+Colors.ENDC+":"+Colors.cyan +
+ Colors.BOLD+repr(list_1h_value[i])+Colors.ENDC).ljust(col_width))
+ print()
+ for i in range(number, -1, -1):
+ print((Colors.red + Colors.BOLD + repr(300-i) +
+ Colors.ENDC).ljust(21), end="")
+ print((Colors.blue+list_7d_key[i]+Colors.ENDC+":"+Colors.cyan+Colors.BOLD+repr(
+ list_7d_value[i])+Colors.ENDC).ljust(col_width + 24), end="")
+ print((Colors.blue+list_24h_key[i]+Colors.ENDC+":"+Colors.cyan+Colors.BOLD+repr(
+ list_24h_value[i])+Colors.ENDC).ljust(col_width+24), end="")
+ print((Colors.blue+list_1h_key[i]+Colors.ENDC+":"+Colors.cyan +
+ Colors.BOLD+repr(list_1h_value[i])+Colors.ENDC).ljust(col_width))
+
+ one = []
+ one.append("7d:\n\n")
+ for i in range(299, 300-number, -1):
+ one.append(repr(list_7d_key[i]))
+ one.append("\t")
+ one.append(repr(list_7d_value[i]))
+ one.append("\n")
+ for i in range(number, -1, -1):
+ one.append(repr(list_7d_key[i]))
+ one.append("\t")
+ one.append(repr(list_7d_value[i]))
+ one.append("\n")
+
+ one.append("\n\n24h:\n\n")
+ for i in range(299, 300-number, -1):
+ one.append(repr(list_24h_key[i]))
+ one.append("\t")
+ one.append(repr(list_24h_value[i]))
+ one.append("\n")
+ for i in range(number, -1, -1):
+ one.append(repr(list_24h_key[i]))
+ one.append("\t")
+ one.append(repr(list_24h_value[i]))
+ one.append("\n")
+
+ one.append("\n\n1h:\n\n")
+ for i in range(299, 300-number, -1):
+ one.append(repr(list_1h_key[i]))
+ one.append("\t")
+ one.append(repr(list_1h_value[i]))
+ one.append("\n")
+ for i in range(number, -1, -1):
+ one.append(repr(list_1h_key[i]))
+ one.append("\t")
+ one.append(repr(list_1h_value[i]))
+ one.append("\n")
+
+ return one
+
+
+class Void_Spawner(object):
+ __metalclass__ = ABCMeta
+
+ def __init__(self):
+ thread = threading.Thread(target=self.run, args=())
+ thread.daemon = True
+ thread.start()
+
+ @abstractmethod
+ def run(self):
+ pass
+
+
+class V_Spawn_cnn(Void_Spawner):
+ def run(self):
+ launch_ais("cnn_type_1")
+
+
+class V_Spawn_ltsm(Void_Spawner):
+ def run(self):
+ launch_ais("ltsm_type_2")
+
+
+class V_Spawn_marionette(Void_Spawner):
+ def run(self):
+ launch_ais("marionette_type_1")
+
+
+class Demon_Father:
+ __metalclass__ = ABCMeta
+
+ def __init__(self, pidfile):
+ self.pidfile = pidfile
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.server_address = ('localhost', 10111)
+
+ def demonize(self):
+ try:
+ pid = os.fork()
+ if pid > 0:
+ sys.exit(0)
+ except OSError as err:
+ sys.stderr.write('fork #1 failed: {0}\n'.format(err))
+ sys.exit(1)
+ os.chdir('/')
+ os.setsid()
+ os.umask(0)
+ try:
+ pid = os.fork()
+ if pid > 0:
+ sys.exit(0)
+ except OSError as err:
+ sys.stderr.write('fork #2 failed: {0}\n'.format(err))
+ sys.exit(1)
+ sys.stdout.flush()
+ sys.stderr.flush()
+ si = open(os.devnull, 'r')
+ so = open(os.devnull, 'a+')
+ se = open(os.devnull, 'a+')
+ os.dup2(si.fileno(), sys.stdin.fileno())
+ os.dup2(so.fileno(), sys.stdout.fileno())
+ os.dup2(se.fileno(), sys.stderr.fileno())
+ atexit.register(self.delpid)
+ pid = str(os.getpid())
+ with open(self.pidfile, 'w+') as f:
+ f.write(pid + '\n')
+
+ def delpid(self):
+ self.pidfile.close()
+ os.remove(self.pidfile)
+
+ def start(self):
+ try:
+ with open(self.pidfile, 'r') as pf:
+ pid = int(pf.read().strip())
+ except IOError:
+ pid = None
+ '''
+ if pid:
+ message = "pidfile {0} already exist. " + "Daemon already running?\n"
+ sys.stderr.write(message.format(self.pidfile))
+ sys.exit(1)
+ '''
+ self.demonize()
+ self.run()
+
+ def stop(self):
+ try:
+ with open(self.pidfile, 'r') as pf:
+ pid = int(pf.read().strip())
+ except IOError:
+ pid = None
+ if not pid:
+ message = "pidfile {0} does not exist. " + "Daemon not running?\n"
+ sys.stderr.write(message.format(self.pidfile))
+ return
+ try:
+ while 1:
+ os.kill(pid, signal.SIGTERM)
+ time.sleep(0.1)
+ except OSError as err:
+ e = str(err.args)
+ if e.find("No such process") > 0:
+ if os.path.exists(self.pidfile):
+ os.remove(self.pidfile)
+ else:
+ print(str(err.args))
+ sys.exit(1)
+
+ def restart(self):
+ self.stop()
+ self.start()
+
+ @abstractmethod
+ def run(self):
+ pass
+
+
+class Demon(Demon_Father):
+ def __init__(self, argparser, pidfile):
+ self.pidfile = pidfile
+ self.connection = []
+ self.client_address = []
+ self.argparser = argparser
+
+ def run(self):
+ premain(self.argparser)
+
+
+def networth():
+ net = float()
+ assets = json.load(open(assets_file))
+ for asset in assets:
+ price = get_info_w_name(api_url_base, asset)["USD"]
+ net += assets[asset] * float(price)
+ return int(net)
+
+
+def alert_1():
+ res1 = get_info_w_name(api_url_base, "doge")["USD"]
+ res2 = get_info_w_name(api_url_base, "eth")["USD"]
+ value = 600000
+ print("%.2f" % (value*float(res1)/float(res2)))
+ if value*float(res1)/float(res2) < 2:
+ vocalize("./mila/alert_1.ogg")
+
+
+def alert_2():
+ res1 = get_info_w_name(api_url_base, "gnt")["USD"]
+ res2 = get_info_w_name(api_url_base, "eth")["USD"]
+ value = 1765
+ print("%.2f" % (value*float(res1)/float(res2)))
+ if value*float(res1)/float(res2) > 2:
+ vocalize("./mila/alert_2.ogg")
+
+
+def alert_3():
+ res1 = get_info_w_name(api_url_base, "ant")["USD"]
+ res2 = get_info_w_name(api_url_base, "eth")["USD"]
+ value = 196
+ print("%.2f" % (value*float(res1)/float(res2)))
+ if value*float(res1)/float(res2) > 2:
+ vocalize("./mila/alert_3.ogg")
+
+
+def alert_4():
+ res1 = get_info_w_name(api_url_base, "sc")["USD"]
+ res2 = get_info_w_name(api_url_base, "eth")["USD"]
+ value = 35695
+ print("%.2f" % (value*float(res1)/float(res2)))
+ if value*float(res1)/float(res2) > 2:
+ vocalize("./mila/alert_4.ogg")
+
+
+def alert_5():
+ res1 = get_info_w_name(api_url_base, "bat")["USD"]
+ res2 = get_info_w_name(api_url_base, "eth")["USD"]
+ value = 4013
+ print("%.2f" % (value*float(res1)/float(res2)))
+ if value*float(res1)/float(res2) > 2:
+ vocalize("./mila/alert_4.ogg")
+
+
+def highpercentdump_bot():
+ return highpercentdump(22)
+
+
+def com_name(name):
+ res = get_info_w_name(api_url_base, name)
+ if res is not None:
+ print(trim(float(res['USD']), 4))
+
+
+def com_cap(name):
+ res = get_info_w_name(api_url_base, name)
+ if res is not None:
+ print(res[0]['market_cap_usd'])
+
+
+def com_rank(name):
+ res = get_info_w_name(api_url_base, name)
+ if res is not None:
+ print(res[0]['rank'])
+
+
+def com_gen(argparser):
+ name = argparser.args.gen[0]
+ cat = argparser.args.gen[1]
+ res = get_info_w_name(api_url_base, name)
+ if res is not None:
+ print(res[0][cat])
+
+
+def com_worth(argparser):
+ net = float()
+ assets = json.load(open(assets_file))
+ for asset in assets:
+ if asset == argparser.args.worth:
+ price = get_info_w_name(api_url_base, asset)["USD"]
+ net = assets[asset] * float(price)
+ print(int(net))
+ break
+
+
+def com_total(argparser):
+ net = float()
+ assets = json.load(open(assets_file))
+ for asset in assets:
+ price = get_info_w_name(api_url_base, asset)["USD"]
+ net += assets[asset] * float(price)
+ print("{:,}".format(int(net)))
+
+
+def com_xx(argparser):
+ value = 1.0
+ name1 = argparser.args.xx[0]
+ name2 = argparser.args.xx[1]
+ res1 = get_info_w_name(api_url_base, name1)["USD"]
+ res2 = get_info_w_name(api_url_base, name2)["USD"]
+ if argparser.args.xxv:
+ value = argparser.args.xxv
+ print(value*float(res1)/float(res2))
+
+
+def com_ava(argparser):
+ currencies = changelly()
+ if currencies is not None:
+ for currency in currencies:
+ if currency == argparser.args.ava:
+ print("YES")
+ return
+ print("NO")
+
+
+def com_avass(argparser):
+ currencies = get_info_w_name(api_url_base_shapeshift, "")
+ for currency in currencies:
+ if currency.lower() == argparser.args.avass:
+ print("YES")
+ return
+ print("NO")
+
+
+def com_cglistall(argparser):
+ currencies = changelly()
+ if currencies is not None:
+ for currency in currencies:
+ print(currency + " ", end="")
+ print()
+
+
+def com_watchlist(argparser):
+ ret = []
+ currencies = changelly()
+ if currencies is not None:
+ for currency in currencies:
+ for item in argparser.args.watchlist:
+ if currency == item:
+ ret.append(item)
+ for item in ret:
+ print(item.upper() + " ", end="")
+ print()
+
+
+def com_ss(argparser):
+ ret = []
+ result = get_info_w_name(api_url_base_shapeshift, "")
+ if not result:
+ return
+ for currency in result:
+ for item in argparser.args.ss:
+ if currency.lower() == item and result[currency]['status'] == "available":
+ ret.append(item)
+ for item in ret:
+ print(item.upper() + " ", end="")
+ print()
+
+
+def alive():
+ print("hived")
+
+
+def get_socket():
+ # use TCP
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ server_address = ("", 10111)
+ sock.bind(server_address)
+ return sock
+
+
+def premain(argparser):
+ try:
+ sock = get_socket()
+ sock.listen(15)
+ vocalize("./mila/hiveup.ogg")
+
+ while True:
+ connection, client_address = sock.accept()
+ command = connection.recv(4096)
+ new_argv = command.decode("utf-8").split(" ")
+ print(new_argv)
+ argparser.parse(new_argv)
+ old_stdout = sys.stdout
+ sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding)
+
+ if argparser.args.name:
+ com_name(argparser.args.name)
+ if argparser.args.cap:
+ com_cap(argparser.args.cap)
+ if argparser.args.rank:
+ com_rank(argparser.args.rank)
+ if argparser.args.gen:
+ com_gen(argparser)
+ if argparser.args.worth:
+ com_worth(argparser)
+ if argparser.args.total:
+ com_total(argparser)
+ if argparser.args.xx:
+ com_xx(argparser)
+ if argparser.args.ava:
+ com_ava(argparser)
+ if argparser.args.al1:
+ alert_1()
+ if argparser.args.al2:
+ alert_2()
+ if argparser.args.al3:
+ alert_3()
+ if argparser.args.al4:
+ alert_4()
+ if argparser.args.al5:
+ alert_5()
+ if argparser.args.avass:
+ com_avass(argparser)
+ if argparser.args.cglistall:
+ com_cglistall(argparser)
+ if argparser.args.watchlist:
+ com_watchlist(argparser)
+ if argparser.args.ss:
+ com_ss(argparser)
+ if argparser.args.dy:
+ highpercentdump(argparser.args.dy)
+ if argparser.args.alive:
+ alive()
+
+ sys.stdout.seek(0)
+ mushi_out = sys.stdout.read()
+ sys.stdout.close()
+ connection.sendall(bytes(mushi_out, "utf-8"))
+ sys.stdout = old_stdout
+ print(mushi_out)
+ except Exception as e:
+ vocalize("./mila/hiveexcept.ogg")
+ if hasattr(e, "message"):
+ print(e.messasge)
+ if hasattr(e, "__doc__"):
+ print(e.__doc__)
+ finally:
+ # vocalize("./mila/hivedown.ogg")
+ # sock.shutdown(socket.SHUT_RDWR)
+ # connection.shutdown(socket.SHUT_RDWR)
+ # sock.close()
+ # connection.close()
+ time.sleep(60)
+
+
+def main():
+ argparser = Argparser()
+ sys.argv.pop(0)
+ argparser.parse(sys.argv)
+ if argparser.args.dbg:
+ try:
+ premain(argparser)
+ except:
+ variables = globals().copy()
+ variables.update(locals())
+ shell = code.InteractiveConsole(variables)
+ shell.interact(banner="DEBUG REPL")
+ else:
+ premain(argparser)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/hived.desktop b/hived.desktop
new file mode 100644
index 0000000..3ae9514
--- /dev/null
+++ b/hived.desktop
@@ -0,0 +1,5 @@
+[Desktop Entry]
+Name=hived
+Exec=/home/bloodstalker/scripts/hived --demon
+Terminal=true
+Type=Application
diff --git a/hivedup.sh b/hivedup.sh
new file mode 100755
index 0000000..489d339
--- /dev/null
+++ b/hivedup.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/sh
+
+PID=$(pgrep hived$)
+if [ -z "$PID" ]; then :;else echo hived;fi