<commit_before>from Song import Song

# http://code.google.com/p/leveldb/
# http://code.google.com/p/py-leveldb/
from leveldb import *

import appinfo
import utils

def dbRepr(o): return utils.betterRepr(o)
def dbUnRepr(s): return eval(s)

class DB:
	def __init__(self, filename):
		self.filename = filename
		self.db = LevelDB(appinfo.userdir + "/" + filename)

	def __getitem__(self, item):
		return dbUnRepr(self.db.Get(dbRepr(item)))

	def __setitem__(self, key, value):
		self.db.Put(dbRepr(key), dbRepr(value))

	def __delitem__(self, key):
		self.db.Delete(dbRepr(key))

class SongStore:
	def __init__(self):
		self.databasedir = databasedir
		self.artistIndex = DB("artistIndex.db")
		self.titleIndex = DB("titleIndex.db")
		self.genreIndex = DB("genreIndex.db")
		self.songStore = DB("songStore.db")

	def add(self, song):
		if self.songStore[song.fingerprint_AcoustID] is None:
			self.songStore[song.fingerprint_AcoustID] = set(song.url)
		else:
			self.songStore[song.fingerprint_AcoustID].add(song.url)

		if self.artistIndex[song.artist] is None:
			self.artistIndex[song.artist] = set(song.fingerprint_AcoustID)
		else:
			self.artistIndex[song.artist].add(song.fingerprint_AcoustID)

		if self.titleIndex[song.title] is None:
			self.titleIndex[song.title] = set(song.fingerprint_AcoustID)
		else:
			self.titleIndex[song.title].add(song.fingerprint_AcoustID)

		if self.genreIndex[song.genre] is None:
			self.genreIndex[song.genre] = set(song.fingerprint_AcoustID)
		else:
			self.genreIndex[song.genre].add(song.fingerprint_AcoustID)

	def addMany(self, songs):
		for song in songs:
			self.add(song)

	def remove(self, song):
		if self.songStore[song.fingerprint_AcoustID]:
			self.songStore[song.fingerprint_AcoustID].remove(song.url)

		if len(self.songStore[song.fingerprint_AcoustID]) == 0:
			self.songStore.remove(song.fingerprint_AcoustID)

		if self.artistIndex[song.artist]:
			self.artistIndex[song.artist].remove(song.fingerprint_AcoustID)

		if len(self.artistIndex[song.artist]) == 0:
			self.artistIndex.remove(song.artist)

		if self.titleIndex[song.title]:
			self.titleIndex[song.title].remove(song.fingerprint_AcoustID)

		if len(self.titleIndex[song.title]) == 0:
			self.titleIndex.remove(song.title)

		if self.genreIndex[song.genre]:
			self.genreIndex[song.genre].remove(song.fingerprint_AcoustID)

		if len(self.genreIndex[song.genre]) == 0:
			self.genreIndex.remove(song.genre)

	def removeMany(self, songs):
		for song in songs:
			self.remove(song)

	def get(self, AcoustId):
		return self.songStore[AcoustId]

	def searchByArtist(self, searchString):
		keys = self.artistIndex.match_prefix(searchString)
		songs = []

		for key in keys:
			songSet = self.songStore[key]
			for song in songSet:
				songs.append(Song(song))

		return songs

	def searchByTitle(self, searchString):
		keys = self.titleIndex.match_prefix(searchString)
		songs = []

		for key in keys:
			songSet = self.titleIndex[key]
			for song in songSet:
				songs.append(Song(song))

		return songs

	def searchByGenre(self, searchString):
		keys = self.genreIndex.match_prefix(searchString)
		songs = []

		for key in keys:
			songSet = self.genreIndex[key]
			for song in songSet:
				songs.append(Song(song))

		return songs

	def search(self, searchString):
		songs = []

		songs = songs + self.searchByArtist(searchString)
		songs = songs + self.searchByTitle(searchString)
		songs = songs + self.searchByGenre(searchString)

		return songs

	def getRandomSongs(self, oldSong=None, limit=1):
		from random import sample
		songs = []

		if oldSong is None:
			keys = sample(self.songStore.match_prefix(''), limit)

			for key in keys:
				songSet = self.songStore[key]
				for song in songSet:
					songs.append(Song(song))

			return songs
		else:

			songs = songs + self.searchByArtist(oldSong.artist)
			songs = songs + self.searchByGenre(oldSong.genre)

			return sample(songs, limit)<commit_msg>Changing over to LevelDB. Still not complete yet<commit_after>from Song import Song

# http://code.google.com/p/leveldb/
# http://code.google.com/p/py-leveldb/
import leveldb

import appinfo
import utils

def dbRepr(o): return utils.betterRepr(o)

def dbUnRepr(s): return eval(s)

class DB:
    def __init__(self, dir):
        self.db = leveldb.LevelDB(appinfo.userdir + "/" + dir)

    def __getitem__(self, item):
        try:
            return dbUnRepr(self.db.Get(dbRepr(item)))
        except KeyError:
            return None

    def __setitem__(self, key, value):
        self.db.Put(dbRepr(key), dbRepr(value))

    def __delitem__(self, key):
        self.db.Delete(dbRepr(key))

    def setDefault(self, key, value):
        if self[key] is not None:
            return self[key]
        else:
            self[key] = value
            return self[key]

    #If not value set at key, it creates a set. Will append value to set
    def setAppend(self, key, valueToAppend):
        value = self.setDefault(key, set())
        value.add(valueToAppend)
        self[key] = value
        return value

    #if key not set does nothing. If it is set then remove the value from the key. If key is empty, removes key
    def setRemove(self, key, valueToRemove):
        if self[key] is not None:
            value = self[key]
            value.remove(valueToRemove)
            if len(value) == 0:
                del self[key]

    def match_prefix(self, searchString):

        keys = []

        for record in self.db.RangeIter():
            if record[0].startsWith(searchString):
                keys.add(record[0])

        return keys

    def getValueSet(self, keys):
        pass

class SongStore:
    def __init__(self):
        self.artistIndex = DB(".artists")
        self.titleIndex = DB(".titles")
        self.genreIndex = DB(".genres")
        self.songStore = DB(".songs")

    def add(self, song):
        self.songStore.setAppend(song.fingerprint_AcoustID, song.url)
        self.artistIndex.setAppend(song.artist, song.fingerprint_AcoustID)
        self.titleIndex.setAppend(song.title, song.fingerprint_AcoustID)
        self.genreIndex.setAppend(song.genre, song.fingerprint_AcoustID)

    def addMany(self, songs):
        for song in songs:
            self.add(song)

    def remove(self, song):
        self.songStore.setRemove(song.fingerprint_AcoustID, song.url)
        self.artistIndex.setRemove(song.artist, song.fingerprint_AcoustID)
        self.titleIndex.setRemove(song.title, song.fingerprint_AcoustID)
        self.genreIndex.setRemove(song.genre, song.fingerprint_AcoustID)

    def removeMany(self, songs):
        for song in songs:
            self.remove(song)

    def get(self, AcoustId):
        return self.songStore[AcoustId]

    def searchByArtist(self, searchString):
        keys = self.artistIndex.match_prefix(searchString)
        songs = []

        for key in keys:
            songSet = self.songStore[key]
            for song in songSet:
                songs.append(Song(song))

        return songs

    def searchByTitle(self, searchString):
        keys = self.titleIndex.match_prefix(searchString)
        songs = []

        for key in keys:
            songSet = self.titleIndex[key]
            for song in songSet:
                songs.append(Song(song))

        return songs

    def searchByGenre(self, searchString):
        keys = self.genreIndex.match_prefix(searchString)
        songs = []

        for key in keys:
            songSet = self.genreIndex[key]
            for song in songSet:
                songs.append(Song(song))

        return songs

    def search(self, searchString):
        songs = []

        songs = songs + self.searchByArtist(searchString)
        songs = songs + self.searchByTitle(searchString)
        songs = songs + self.searchByGenre(searchString)

        return songs

    def getRandomSongs(self, oldSong=None, limit=1):
        from random import sample

        songs = []

        if oldSong is None:
            keys = sample(self.songStore.match_prefix(''), limit)

            for key in keys:
                songSet = self.songStore[key]
                for song in songSet:
                    songs.append(Song(song))

            return songs
        else:
            songs = songs + self.searchByArtist(oldSong.artist)
            songs = songs + self.searchByGenre(oldSong.genre)

            return sample(songs, limit)<|endoftext|>


<commit_before>import sys
import sublime
import datetime
import codecs
import os, os.path
from threading import Thread
import signal, subprocess
import json
import webbrowser
from hashlib import sha1

is_sublime_text_3 = int(sublime.version()) >= 3000

if is_sublime_text_3:
    from .base_command import BaseCommand
    from .progress_notifier import ProgressNotifier
    import urllib.request as urllib2
else:
    from base_command import BaseCommand
    from progress_notifier import ProgressNotifier
    import urllib2

class GulpCommand(BaseCommand):
    cache_file_name = ".sublime-gulp.cache"
    log_file_name = 'sublime-gulp.log'

    def work(self):
        self.set_instance_variables()
        self.list_gulp_files()

    def set_instance_variables(self):
        self.gulp_files = []
        self.env = Env(self.settings)

    def list_gulp_files(self):
        self.append_paths()
        if len(self.gulp_files) > 0:
            self.choose_file()
        else:
            self.error_message("gulpfile.js not found!")

    def append_paths(self):
        self.folders = []
        for folder_path in self.window.folders():
            self.append_to_gulp_files(folder_path)
            for inner_folder in self.settings.get("gulpfile_paths", []):
                self.append_to_gulp_files(os.path.join(folder_path, inner_folder))

    def append_to_gulp_files(self, folder_path):
        gulpfile_path = os.path.join(folder_path, "gulpfile.js")
        self.folders.append(folder_path)
        if os.path.exists(gulpfile_path):
            self.gulp_files.append(gulpfile_path)

    def choose_file(self):
        if len(self.gulp_files) == 1:
            self.show_tasks_from_gulp_file(0)
        else:
            self.show_quick_panel(self.gulp_files, self.show_tasks_from_gulp_file)

    def show_tasks_from_gulp_file(self, file_index):
        if file_index > -1:
            self.working_dir = os.path.dirname(self.gulp_files[file_index])
            if self.task_name:
                self.run_gulp_task()
            else:
                self.defer(self.show_tasks)

    def show_tasks(self):
        self.tasks = self.list_tasks()
        if self.tasks is not None:
            self.show_quick_panel(self.tasks, self.task_list_callback)

    def list_tasks(self):
        try:
            self.callcount = 0
            json_result = self.fetch_json()
        except TypeError as e:
            self.error_message("Could not read available tasks.\nMaybe the JSON cache (.sublime-gulp.cache) is malformed?")
        except Exception as e:
            self.error_message(str(e))
        else:
            tasks = [[name, self.dependencies_text(task)] for name, task in json_result.items()]
            return sorted(tasks, key = lambda task: task)

    def dependencies_text(self, task):
        return "Dependencies: " + task['dependencies'] if task['dependencies'] else ""

    # Refactor
    def fetch_json(self):
        jsonfilename = os.path.join(self.working_dir, self.cache_file_name)
        gulpfile = os.path.join(self.working_dir, "gulpfile.js") # .coffee ?
        data = None

        if os.path.exists(jsonfilename):
            filesha1 = Security.hashfile(gulpfile)
            json_data = open(jsonfilename)

            try:
                data = json.load(json_data)
                if gulpfile in data and data[gulpfile]["sha1"] == filesha1:
                    return data[gulpfile]["tasks"]
            finally:
                json_data.close()

        self.callcount += 1

        if self.callcount == 1:
            return self.write_to_cache()

        if data is None:
            raise Exception("Could not write to cache gulpfile.")

        raise Exception("Sha1 from gulp cache ({0}) is not equal to calculated ({1}).\nTry erasing the cache and running Gulp again.".format(data[gulpfile]["sha1"], filesha1))

    def write_to_cache(self):
        package_path = os.path.join(sublime.packages_path(), self.package_name)

        args = r'node "%s/write_tasks_to_cache.js"' % package_path

        process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self.env.get_path_with_exec_args(), cwd=self.working_dir, shell=True)
        (stdout, stderr) = process.communicate()

        if 127 == process.returncode:
            raise Exception("\"node\" command not found.\nPlease be sure to have nodejs installed on your system and in your PATH (more info in the README).")
        elif stderr:
            self.log_errors(stderr)
            raise Exception("There was an error running gulp, make sure gulp is running correctly in your project.\nFor more info check the sublime-gulp.log file")

        return self.fetch_json()

    def log_errors(self, text):
        if not self.settings.get("log_errors", True):
            return
        log_path = self.working_dir + "/" + self.log_file_name
        header = "Remember that you can report errors and get help in https://github.com/NicoSantangelo/sublime-gulp" if not os.path.isfile(log_path) else ""
        with codecs.open(log_path, 'a', "utf-8") as log_file:
            log_file.write(header + "\n\n" + str(datetime.datetime.now().strftime("%m-%d-%Y %H:%M")) + ":\n" + text.decode('utf-8'))

    def task_list_callback(self, task_index):
        if task_index > -1:
            self.task_name = self.tasks[task_index][0]
            self.run_gulp_task()

    def run_gulp_task(self):
        task = self.construct_gulp_task()
        Thread(target = self.run_process, args = (task, )).start() # Option to kill on timeout?

    def construct_gulp_task(self):
        self.show_output_panel("Running '%s'...\n" % self.task_name)
        return r"gulp %s" % self.task_name

    def run_process(self, task):
        process = CrossPlatformProcess(self)
        process.run(task)
        stdout, stderr = process.communicate(self.append_to_output_view_in_main_thread)
        self.defer_sync(lambda: self.finish(stdout, stderr))

    def finish(self, stdout, stderr):
        finish_message = "gulp %s finished %s" % (self.task_name, "with some errors." if stderr else "!")
        self.status_message(finish_message)
        if not self.silent:
            self.set_output_close_on_timeout()
        elif stderr and self.settings.get("show_silent_errors", False):
            self.silent = False
            self.show_output_panel("Running '%s'...\n" % self.task_name)
            self.append_to_output_view(stdout)
            self.append_to_output_view(stderr)
            self.silent = True

class GulpKillCommand(BaseCommand):
    def work(self):
        if ProcessCache.empty():
            self.status_message("There are no running tasks")
        else:
            self.show_output_panel("\nFinishing the following running tasks:\n")
            ProcessCache.each(lambda process: self.append_to_output_view("$ %s \n" % process.last_command))
            ProcessCache.kill_all()
            self.append_to_output_view("\nAll running tasks killed!\n")

class GulpShowPanelCommand(BaseCommand):
    def work(self):
        self.show_panel()

class GulpPluginsCommand(BaseCommand):
    def work(self):
        self.plugins = None
        self.request_plugin_list()

    def request_plugin_list(self):
        progress = ProgressNotifier("Gulp: Working")
        thread = PluginRegistryCall()
        thread.start()
        self.handle_thread(thread, progress)

    def handle_thread(self, thread, progress):
         if thread.is_alive() or thread.result == False:
            sublime.set_timeout(lambda: self.handle_thread(thread, progress), 100)
         else:
            progress.stop()
            plugin_response = json.loads(thread.result.decode('utf-8'))
            if plugin_response["timed_out"]:
                self.error_message("Sadly the request timed out, try again later.")
            else:
                self.plugins = PluginList(plugin_response)
                self.show_quick_panel(self.plugins.quick_panel_list(), self.open_in_browser, font = 0)

    def open_in_browser(self, index = -1):
        if index >= 0 and index < self.plugins.length:
            webbrowser.open_new(self.plugins.get(index).get('homepage'))

class CrossPlatformProcess():
    def __init__(self, command):
        self.path = command.env.get_path_with_exec_args()
        self.working_dir = command.working_dir
        self.last_command = ""

    def run(self, command):
        self.process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self.path, cwd=self.working_dir, shell=True, preexec_fn=self._preexec_val())
        self.last_command = command
        ProcessCache.add(self)
        return self

    def _preexec_val(self):
        return os.setsid if sublime.platform() != "windows" else None

    def communicate(self, fn = lambda x:None):
        stdout, stderr = self.pipe(fn)
        self.process.communicate()
        self.terminate()
        return (stdout, stderr)

    def pipe(self, fn):
        return [self._pipe_output(output, fn) for output in [self.process.stdout, self.process.stderr]]

    def _pipe_output(self, output, fn):
        output_text = ""
        for line in output:
            output_line = self.decode_line(line)
            output_text += output_line
            fn(output_line)
        return output_text

    def decode_line(self, line):
        line = line.rstrip()
        return str(line.decode('utf-8') if sys.version_info >= (3, 0) else line) + "\n"

    def read(self, output):
        return output.read().decode('utf-8')

    def terminate(self):
        if self.is_alive():
            self.process.terminate()
        ProcessCache.remove(self)

    def is_alive(self):
        return self.process.poll() is None

    def kill(self):
        pid = self.process.pid
        if sublime.platform() == "windows":
            kill_process = subprocess.Popen(['taskkill', '/F', '/T', '/PID', str(pid)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
            kill_process.communicate()
        else:
            os.killpg(pid, signal.SIGTERM)
        ProcessCache.remove(self)

class ProcessCache():
    _procs = []

    @classmethod
    def add(cls, process):
       cls._procs.append(process)

    @classmethod
    def remove(cls, process):
        if process in cls._procs:
            cls._procs.remove(process)

    @classmethod
    def kill_all(cls):
        cls.each(lambda process: process.kill())
        cls.clear()

    @classmethod
    def each(cls, fn):
        for process in cls._procs:
            fn(process)

    @classmethod
    def empty(cls):
        return len(cls._procs) == 0

    @classmethod
    def clear(cls):
        del cls._procs[:]

class Env():
    def __init__(self, settings):
        self.exec_args = settings.get('exec_args', False)

    def get_path(self):
        path = os.environ['PATH']
        if self.exec_args:
            path = self.exec_args.get('path', os.environ['PATH'])
        return str(path)

    def get_path_with_exec_args(self):
        env = os.environ.copy()
        if self.exec_args:
            path = str(self.exec_args.get('path', ''))
            if path:
                env['PATH'] = path
        return env

class Security():
    @classmethod
    def hashfile(cls, filename):
        with open(filename, mode='rb') as f:
            filehash = sha1()
            content = f.read();
            filehash.update(str("blob " + str(len(content)) + "\0").encode('UTF-8'))
            filehash.update(content)
            return filehash.hexdigest()

class PluginList():
    def __init__(self, plugins_response):
        self.plugins = [Plugin(plugin_json) for plugin_json in plugins_response["hits"]["hits"]]
        self.length = len(self.plugins)

    def get(self, index):
        if index >= 0 and index < self.length:
            return self.plugins[index]

    def quick_panel_list(self):
        return [ [plugin.get('name') + ' (v' + plugin.get('version') + ')', plugin.get('description')] for plugin in self.plugins ]

class Plugin():
    def __init__(self, plugin_json):
        self.plugin = plugin_json

    def get(self, property):
        return self.plugin['fields'][property][0] if self.has(property) else ''

    def has(self, property):
        return 'fields' in self.plugin and property in self.plugin['fields']

class PluginRegistryCall(Thread):
    url = "http://registry.gulpjs.com/_search?fields=name,description,author,homepage,version&from=20&q=keywords:gulpplugin,gulpfriendly&size=750"

    def __init__(self, timeout = 5):
        self.timeout = timeout
        self.result = None
        Thread.__init__(self)

    def run(self):
        try:
            request = urllib2.Request(self.url, None, headers = { "User-Agent": "Sublime Text" })
            http_file = urllib2.urlopen(request, timeout = self.timeout)
            self.result = http_file.read()
            return

        except urllib2.HTTPError as e:
            err = 'Gulp: HTTP error %s contacting gulpjs registry' % (str(e.code))
        except urllib2.URLError as e:
            err = 'Gulp: URL error %s contacting gulpjs registry' % (str(e.reason))

        sublime.error_message(err)
        self.result = False<commit_msg>Use readline to avoid buffering and allow realtime stdout in ST2<commit_after>import sys
import sublime
import datetime
import codecs
import os, os.path
from threading import Thread
import signal, subprocess
import json
import webbrowser
from hashlib import sha1

is_sublime_text_3 = int(sublime.version()) >= 3000

if is_sublime_text_3:
    from .base_command import BaseCommand
    from .progress_notifier import ProgressNotifier
    import urllib.request as urllib2
else:
    from base_command import BaseCommand
    from progress_notifier import ProgressNotifier
    import urllib2

class GulpCommand(BaseCommand):
    cache_file_name = ".sublime-gulp.cache"
    log_file_name = 'sublime-gulp.log'

    def work(self):
        self.set_instance_variables()
        self.list_gulp_files()

    def set_instance_variables(self):
        self.gulp_files = []
        self.env = Env(self.settings)

    def list_gulp_files(self):
        self.append_paths()
        if len(self.gulp_files) > 0:
            self.choose_file()
        else:
            self.error_message("gulpfile.js not found!")

    def append_paths(self):
        self.folders = []
        for folder_path in self.window.folders():
            self.append_to_gulp_files(folder_path)
            for inner_folder in self.settings.get("gulpfile_paths", []):
                self.append_to_gulp_files(os.path.join(folder_path, inner_folder))

    def append_to_gulp_files(self, folder_path):
        gulpfile_path = os.path.join(folder_path, "gulpfile.js")
        self.folders.append(folder_path)
        if os.path.exists(gulpfile_path):
            self.gulp_files.append(gulpfile_path)

    def choose_file(self):
        if len(self.gulp_files) == 1:
            self.show_tasks_from_gulp_file(0)
        else:
            self.show_quick_panel(self.gulp_files, self.show_tasks_from_gulp_file)

    def show_tasks_from_gulp_file(self, file_index):
        if file_index > -1:
            self.working_dir = os.path.dirname(self.gulp_files[file_index])
            if self.task_name:
                self.run_gulp_task()
            else:
                self.defer(self.show_tasks)

    def show_tasks(self):
        self.tasks = self.list_tasks()
        if self.tasks is not None:
            self.show_quick_panel(self.tasks, self.task_list_callback)

    def list_tasks(self):
        try:
            self.callcount = 0
            json_result = self.fetch_json()
        except TypeError as e:
            self.error_message("Could not read available tasks.\nMaybe the JSON cache (.sublime-gulp.cache) is malformed?")
        except Exception as e:
            self.error_message(str(e))
        else:
            tasks = [[name, self.dependencies_text(task)] for name, task in json_result.items()]
            return sorted(tasks, key = lambda task: task)

    def dependencies_text(self, task):
        return "Dependencies: " + task['dependencies'] if task['dependencies'] else ""

    # Refactor
    def fetch_json(self):
        jsonfilename = os.path.join(self.working_dir, self.cache_file_name)
        gulpfile = os.path.join(self.working_dir, "gulpfile.js") # .coffee ?
        data = None

        if os.path.exists(jsonfilename):
            filesha1 = Security.hashfile(gulpfile)
            json_data = open(jsonfilename)

            try:
                data = json.load(json_data)
                if gulpfile in data and data[gulpfile]["sha1"] == filesha1:
                    return data[gulpfile]["tasks"]
            finally:
                json_data.close()

        self.callcount += 1

        if self.callcount == 1:
            return self.write_to_cache()

        if data is None:
            raise Exception("Could not write to cache gulpfile.")

        raise Exception("Sha1 from gulp cache ({0}) is not equal to calculated ({1}).\nTry erasing the cache and running Gulp again.".format(data[gulpfile]["sha1"], filesha1))

    def write_to_cache(self):
        package_path = os.path.join(sublime.packages_path(), self.package_name)

        args = r'node "%s/write_tasks_to_cache.js"' % package_path

        process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self.env.get_path_with_exec_args(), cwd=self.working_dir, shell=True)
        (stdout, stderr) = process.communicate()

        if 127 == process.returncode:
            raise Exception("\"node\" command not found.\nPlease be sure to have nodejs installed on your system and in your PATH (more info in the README).")
        elif stderr:
            self.log_errors(stderr)
            raise Exception("There was an error running gulp, make sure gulp is running correctly in your project.\nFor more info check the sublime-gulp.log file")

        return self.fetch_json()

    def log_errors(self, text):
        if not self.settings.get("log_errors", True):
            return
        log_path = self.working_dir + "/" + self.log_file_name
        header = "Remember that you can report errors and get help in https://github.com/NicoSantangelo/sublime-gulp" if not os.path.isfile(log_path) else ""
        with codecs.open(log_path, 'a', "utf-8") as log_file:
            log_file.write(header + "\n\n" + str(datetime.datetime.now().strftime("%m-%d-%Y %H:%M")) + ":\n" + text.decode('utf-8'))

    def task_list_callback(self, task_index):
        if task_index > -1:
            self.task_name = self.tasks[task_index][0]
            self.run_gulp_task()

    def run_gulp_task(self):
        task = self.construct_gulp_task()
        Thread(target = self.run_process, args = (task, )).start() # Option to kill on timeout?

    def construct_gulp_task(self):
        self.show_output_panel("Running '%s'...\n" % self.task_name)
        return r"gulp %s" % self.task_name

    def run_process(self, task):
        process = CrossPlatformProcess(self)
        process.run(task)
        stdout, stderr = process.communicate(self.append_to_output_view_in_main_thread)
        self.defer_sync(lambda: self.finish(stdout, stderr))

    def finish(self, stdout, stderr):
        finish_message = "gulp %s finished %s" % (self.task_name, "with some errors." if stderr else "!")
        self.status_message(finish_message)
        if not self.silent:
            self.set_output_close_on_timeout()
        elif stderr and self.settings.get("show_silent_errors", False):
            self.silent = False
            self.show_output_panel("Running '%s'...\n" % self.task_name)
            self.append_to_output_view(stdout)
            self.append_to_output_view(stderr)
            self.silent = True

class GulpKillCommand(BaseCommand):
    def work(self):
        if ProcessCache.empty():
            self.status_message("There are no running tasks")
        else:
            self.show_output_panel("\nFinishing the following running tasks:\n")
            ProcessCache.each(lambda process: self.append_to_output_view("$ %s \n" % process.last_command))
            ProcessCache.kill_all()
            self.append_to_output_view("\nAll running tasks killed!\n")

class GulpShowPanelCommand(BaseCommand):
    def work(self):
        self.show_panel()

class GulpPluginsCommand(BaseCommand):
    def work(self):
        self.plugins = None
        self.request_plugin_list()

    def request_plugin_list(self):
        progress = ProgressNotifier("Gulp: Working")
        thread = PluginRegistryCall()
        thread.start()
        self.handle_thread(thread, progress)

    def handle_thread(self, thread, progress):
         if thread.is_alive() or thread.result == False:
            sublime.set_timeout(lambda: self.handle_thread(thread, progress), 100)
         else:
            progress.stop()
            plugin_response = json.loads(thread.result.decode('utf-8'))
            if plugin_response["timed_out"]:
                self.error_message("Sadly the request timed out, try again later.")
            else:
                self.plugins = PluginList(plugin_response)
                self.show_quick_panel(self.plugins.quick_panel_list(), self.open_in_browser, font = 0)

    def open_in_browser(self, index = -1):
        if index >= 0 and index < self.plugins.length:
            webbrowser.open_new(self.plugins.get(index).get('homepage'))

class CrossPlatformProcess():
    def __init__(self, command):
        self.path = command.env.get_path_with_exec_args()
        self.working_dir = command.working_dir
        self.last_command = ""

    def run(self, command):
        self.process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self.path, cwd=self.working_dir, shell=True, preexec_fn=self._preexec_val())
        self.last_command = command
        ProcessCache.add(self)
        return self

    def _preexec_val(self):
        return os.setsid if sublime.platform() != "windows" else None

    def communicate(self, fn = lambda x:None):
        stdout, stderr = self.pipe(fn)
        self.process.communicate()
        self.terminate()
        return (stdout, stderr)

    def pipe(self, fn):
        return [self._pipe_output(output, fn) for output in [self.process.stdout, self.process.stderr]]

    def _pipe_output(self, output, fn):
        output_text = ""
        while True:
            line = output.readline()
            if not line: break
            output_line = self.decode_line(line)
            output_text += output_line
            fn(output_line)
        return output_text

    def decode_line(self, line):
        line = line.rstrip()
        return str(line.decode('utf-8') if sys.version_info >= (3, 0) else line) + "\n"

    def read(self, output):
        return output.read().decode('utf-8')

    def terminate(self):
        if self.is_alive():
            self.process.terminate()
        ProcessCache.remove(self)

    def is_alive(self):
        return self.process.poll() is None

    def kill(self):
        pid = self.process.pid
        if sublime.platform() == "windows":
            kill_process = subprocess.Popen(['taskkill', '/F', '/T', '/PID', str(pid)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
            kill_process.communicate()
        else:
            os.killpg(pid, signal.SIGTERM)
        ProcessCache.remove(self)

class ProcessCache():
    _procs = []

    @classmethod
    def add(cls, process):
       cls._procs.append(process)

    @classmethod
    def remove(cls, process):
        if process in cls._procs:
            cls._procs.remove(process)

    @classmethod
    def kill_all(cls):
        cls.each(lambda process: process.kill())
        cls.clear()

    @classmethod
    def each(cls, fn):
        for process in cls._procs:
            fn(process)

    @classmethod
    def empty(cls):
        return len(cls._procs) == 0

    @classmethod
    def clear(cls):
        del cls._procs[:]

class Env():
    def __init__(self, settings):
        self.exec_args = settings.get('exec_args', False)

    def get_path(self):
        path = os.environ['PATH']
        if self.exec_args:
            path = self.exec_args.get('path', os.environ['PATH'])
        return str(path)

    def get_path_with_exec_args(self):
        env = os.environ.copy()
        if self.exec_args:
            path = str(self.exec_args.get('path', ''))
            if path:
                env['PATH'] = path
        return env

class Security():
    @classmethod
    def hashfile(cls, filename):
        with open(filename, mode='rb') as f:
            filehash = sha1()
            content = f.read();
            filehash.update(str("blob " + str(len(content)) + "\0").encode('UTF-8'))
            filehash.update(content)
            return filehash.hexdigest()

class PluginList():
    def __init__(self, plugins_response):
        self.plugins = [Plugin(plugin_json) for plugin_json in plugins_response["hits"]["hits"]]
        self.length = len(self.plugins)

    def get(self, index):
        if index >= 0 and index < self.length:
            return self.plugins[index]

    def quick_panel_list(self):
        return [ [plugin.get('name') + ' (v' + plugin.get('version') + ')', plugin.get('description')] for plugin in self.plugins ]

class Plugin():
    def __init__(self, plugin_json):
        self.plugin = plugin_json

    def get(self, property):
        return self.plugin['fields'][property][0] if self.has(property) else ''

    def has(self, property):
        return 'fields' in self.plugin and property in self.plugin['fields']

class PluginRegistryCall(Thread):
    url = "http://registry.gulpjs.com/_search?fields=name,description,author,homepage,version&from=20&q=keywords:gulpplugin,gulpfriendly&size=750"

    def __init__(self, timeout = 5):
        self.timeout = timeout
        self.result = None
        Thread.__init__(self)

    def run(self):
        try:
            request = urllib2.Request(self.url, None, headers = { "User-Agent": "Sublime Text" })
            http_file = urllib2.urlopen(request, timeout = self.timeout)
            self.result = http_file.read()
            return

        except urllib2.HTTPError as e:
            err = 'Gulp: HTTP error %s contacting gulpjs registry' % (str(e.code))
        except urllib2.URLError as e:
            err = 'Gulp: URL error %s contacting gulpjs registry' % (str(e.reason))

        sublime.error_message(err)
        self.result = False<|endoftext|>


<commit_before>import numpy as np
import sys
import nrrd

if (len(sys.argv) < 3):
    print 'Error: missing arguments!'
    print 'e.g. python SortNG-SG.py NG.nrrd SG.nrrd'
else:

    print 'Checking intensity for ', str(sys.argv[1]), ' against the intensity of ', str(sys.argv[2]), '...'

    readdata, op1 = nrrd.read(str(sys.argv[1]))

    im1 = readdata

    readdata, op2 = nrrd.read(str(sys.argv[2]))
    im2 = readdata

    if (im1.size <> im2.size):
        print '\n\nError: Images must be the same size!!'
    else:

        if (im1.sum < im2.sum):
            print 'swapping the files due to inconsistency in assignment...'
            nrrd.write(str(sys.argv[1]), im2, options=op2)
            nrrd.write(str(sys.argv[2]), im1, options=op1)
        else:
            print 'images appear to be correctly assigned'
        print 'Done.'

<commit_msg>Reporting values added<commit_after>import numpy as np
import sys
import nrrd

if (len(sys.argv) < 3):
    print 'Error: missing arguments!'
    print 'e.g. python SortNG-SG.py NG.nrrd SG.nrrd'
else:

    print 'Checking intensity for ', str(sys.argv[1]), ' against the intensity of ', str(sys.argv[2]), '...'

    readdata, op1 = nrrd.read(str(sys.argv[1]))

    im1 = readdata

    readdata, op2 = nrrd.read(str(sys.argv[2]))
    im2 = readdata

    if (im1.size <> im2.size):
        print '\n\nError: Images must be the same size!!'
    else:

        print 'NG:%s SG:%s' %(str(im1.sum), str(im2.sum))
        if (im1.sum < im2.sum):
            print 'swapping the files due to inconsistency in assignment...'
            nrrd.write(str(sys.argv[1]), im2, options=op2)
            nrrd.write(str(sys.argv[2]), im1, options=op1)
        else:
            print 'images appear to be correctly assigned'
        print 'Done.'

<|endoftext|>


<commit_before># Copyright 2009 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Crowdguru sample application using the XMPP service on Google App Engine."""

import datetime

from google.appengine.api import datastore_types
from google.appengine.api import xmpp
from google.appengine.datastore import entity_pb
from google.appengine.ext import ndb
from google.appengine.ext.webapp import xmpp_handlers
import webapp2
from webapp2_extras import jinja2

PONDER_MSG = 'Hmm. Let me think on that a bit.'
TELLME_MSG = 'While I\'m thinking, perhaps you can answer me this: {}'
SOMEONE_ANSWERED_MSG = ('We seek those who are wise and fast. One out of two '
                        'is not enough. Another has answered my question.')
ANSWER_INTRO_MSG = 'You asked me: {}'
ANSWER_MSG = 'I have thought long and hard, and concluded: {}'
WAIT_MSG = ('Please! One question at a time! You can ask me another once you '
            'have an answer to your current question.')
THANKS_MSG = 'Thank you for your wisdom.'
TELLME_THANKS_MSG = THANKS_MSG + ' I\'m still thinking about your question.'
EMPTYQ_MSG = 'Sorry, I don\'t have anything to ask you at the moment.'
HELP_MSG = ('I am the amazing Crowd Guru. Ask me a question by typing '
            '\'/tellme the meaning of life\', and I will answer you forthwith! '
            'To learn more, go to {}/')
MAX_ANSWER_TIME = 120

# TODO(dhermes): Get this into NDB.
# http://code.google.com/p/appengine-ndb-experiment/issues/detail?id=235
class IMProperty(ndb.Property):
    """A custom property for handling IM objects."""

    def _validate(self, value):
        """Validator to make sure value is an instance of datastore_types.IM.

        Args:
            value: The value to be validated. Should be an instance of
                datastore_types.IM.

        Raises:
            TypeError: If value is not an instance of datastore_types.IM.
        """
        if not isinstance(value, datastore_types.IM):
            raise TypeError('expected an IM, got {!r}'.format(value))

    def _db_set_value(self, v, p, value):
        """Method to customize the way the entity is sent to the datastore.

        Sets the entity meaning to GD_IM and sets the string value to the string
        value of the IM object. The constructor for IM is written in such a way
        that IM(str(im_value)) == im_value and str_value == str(IM(str_value)).

        Args:
            v: Mutable value of Property Message object.
            p: A Property Message object (a protocol buffer).
            value: The value currently set for the IMProperty.
        """
        v.set_stringvalue(str(value))
        p.set_meaning(entity_pb.Property.GD_IM)

    def _db_get_value(self, v, p):
        """Method to customize the way the entity is built from the datastore.

        Args:
            v: Immutable value of Property Message object.
            p: A Property Message object (a protocol buffer).

        Returns:
            A datastore_types.IM instance built from the string in the
                datastore, unless no string was stored, then returns None.

        Raises:
            ValueError: If the stored entity meaning is not GD_IM.
        """
        if not v.has_stringvalue():
            return None
        meaning = p.meaning()
        if meaning != entity_pb.Property.GD_IM:
            raise ValueError('Value stored not an IM.')
        return datastore_types.IM(v.stringvalue())

class Question(ndb.Model):
    """Model to hold questions that the Guru can answer."""
    question = ndb.TextProperty(required=True)
    asker = IMProperty(required=True)
    asked = ndb.DateTimeProperty(required=True, auto_now_add=True)
    suspended = ndb.BooleanProperty(required=True)

    assignees = IMProperty(repeated=True)
    last_assigned = ndb.DateTimeProperty()

    answer = ndb.TextProperty(indexed=True)
    answerer = IMProperty()
    answered = ndb.DateTimeProperty()

    @staticmethod
    @ndb.transactional
    def _try_assign(key, user, expiry):
        """Assigns and returns the question if it's not assigned already.

        Args:
            key: ndb.Key: The key of a Question to try and assign.
            user: datastore_types.IM: The user to assign the question to.
            expiry: datetime.datetime: The expiry date of the question.

        Returns:
            The Question object. If it was already assigned, no change is made.
        """
        question = key.get()
        if not question.last_assigned or question.last_assigned < expiry:
            question.assignees.append(user)
            question.last_assigned = datetime.datetime.now()
            question.put()
        return question

    @classmethod
    def assign_question(cls, user):
        """Gets an unanswered question and assigns it to a user to answer.

        Args:
            user: datastore_types.IM: The identity of the user to assign a
                question to.

        Returns:
            The Question entity assigned to the user, or None if there are no
                unanswered questions.
        """
        question = None
        while question is None or user not in question.assignees:
            # Assignments made before this timestamp have expired.
            expiry = (datetime.datetime.now()
                      - datetime.timedelta(seconds=MAX_ANSWER_TIME))

            # Find a candidate question
            query = cls.query(cls.answerer == None, cls.last_assigned < expiry)
            # If a question has never been assigned, order by when it was asked
            query = query.order(cls.last_assigned, cls.asked)
            candidates = [candidate for candidate in query.fetch(2)
                          if candidate.asker != user]
            if not candidates:
                # No valid questions in queue.
                break

            # Try and assign it
            question = cls._try_assign(candidates[0].key, user, expiry)

        # Expire the assignment after a couple of minutes
        return question

    @ndb.transactional
    def unassign(self, user):
        """Unassigns the given user from this question.

        Args:
            user: datastore_types.IM: The user who will no longer be answering
                this question.
        """
        question = self.key.get()
        if user in question.assignees:
            question.assignees.remove(user)
            question.put()

    @classmethod
    def get_asked(cls, user):
        """Returns the user's outstanding asked question, if any.

        Args:
            user: datastore_types.IM: The identity of the user asking.

        Returns:
            An unanswered Question entity asked by the user, or None if there
                are no unanswered questions.
        """
        query = cls.query(cls.asker == user, cls.answer == None)
        return query.get()

    @classmethod
    def get_answering(cls, user):
        """Returns the question the user is answering, if any.

        Args:
            user: datastore_types.IM: The identity of the user answering.

        Returns:
            An unanswered Question entity assigned to the user, or None if there
                are no unanswered questions.
        """
        query = cls.query(cls.assignees == user, cls.answer == None)
        return query.get()

def bare_jid(sender):
    """Identify the user by bare jid.

    See http://wiki.xmpp.org/web/Jabber_Resources for more details.

    Args:
        sender: String; A jabber or XMPP sender.

    Returns:
        The bare Jabber ID of the sender.
    """
    return sender.split('/')[0]

class XmppHandler(xmpp_handlers.CommandHandler):
    """Handler class for all XMPP activity."""

    def unhandled_command(self, message=None):
        """Shows help text for commands which have no handler.

        Args:
            message: xmpp.Message: The message that was sent by the user.
        """
        message.reply(HELP_MSG.format(self.request.host_url))

    def askme_command(self, message=None):
        """Responds to the /askme command.

        Args:
            message: xmpp.Message: The message that was sent by the user.
        """
        im_from = datastore_types.IM('xmpp', bare_jid(message.sender))
        currently_answering = Question.get_answering(im_from)
        question = Question.assign_question(im_from)
        if question:
            message.reply(TELLME_MSG.format(question.question))
        else:
            message.reply(EMPTYQ_MSG)
        # Don't unassign their current question until we've picked a new one.
        if currently_answering:
            currently_answering.unassign(im_from)

    def text_message(self, message=None):
        """Called when a message not prefixed by a /cmd is sent to the XMPP bot.

        Args:
            message: xmpp.Message: The message that was sent by the user.
        """
        im_from = datastore_types.IM('xmpp', bare_jid(message.sender))
        question = Question.get_answering(im_from)
        if question:
            other_assignees = question.assignees
            other_assignees.remove(im_from)

            # Answering a question
            question.answer = message.arg
            question.answerer = im_from
            question.assignees = []
            question.answered = datetime.datetime.now()
            question.put()

            # Send the answer to the asker
            xmpp.send_message([question.asker.address],
                              ANSWER_INTRO_MSG.format(question.question))
            xmpp.send_message([question.asker.address],
                              ANSWER_MSG.format(message.arg))

            # Send acknowledgement to the answerer
            asked_question = Question.get_asked(im_from)
            if asked_question:
                message.reply(TELLME_THANKS_MSG)
            else:
                message.reply(THANKS_MSG)

            # Tell any other assignees their help is no longer required
            if other_assignees:
                xmpp.send_message([user.address for user in other_assignees],
                                  SOMEONE_ANSWERED_MSG)
        else:
            self.unhandled_command(message)

    def tellme_command(self, message=None):
        """Handles /tellme requests, asking the Guru a question.

        Args:
            message: xmpp.Message: The message that was sent by the user.
        """
        im_from = datastore_types.IM('xmpp', bare_jid(message.sender))
        asked_question = Question.get_asked(im_from)

        if asked_question:
            # Already have a question
            message.reply(WAIT_MSG)
        else:
            # Asking a question
            asked_question = Question(question=message.arg, asker=im_from)
            asked_question.put()

            currently_answering = Question.get_answering(im_from)
            if not currently_answering:
                # Try and find one for them to answer
                question = Question.assign_question(im_from)
                if question:
                    message.reply(TELLME_MSG.format(question.question))
                    return
            message.reply(PONDER_MSG)

class XmppPresenceHandler(webapp2.RequestHandler):
    """Handler class for XMPP status updates."""

    def post(self, status):
        """POST handler for XMPP presence.

        Args:
            status: A string which will be either available or unavailable
               and will indicate the status of the user.
        """
        sender = self.request.get('from')
        im_from = datastore_types.IM('xmpp', bare_jid(sender))
        suspend = (status == 'unavailable')
        query = Question.filter(Question.asker == im_from,
                                Question.answer == None,
                                Question.suspended == not suspend)
        question = query.get()
        if question:
            question.suspended = suspend
            question.put()

class LatestHandler(webapp2.RequestHandler):
    """Displays the most recently answered questions."""

    @webapp2.cached_property
    def jinja2(self):
        """Cached property holding a Jinja2 instance.

        Returns:
            A Jinja2 object for the current app.
        """
        return jinja2.get_jinja2(app=self.app)

    def render_response(self, template, **context):
        """Use Jinja2 instance to render template and write to output.

        Args:
            template: filename (relative to $PROJECT/templates) that we are
                rendering.
            context: keyword arguments corresponding to variables in template.
        """
        rendered_value = self.jinja2.render_template(template, **context)
        self.response.write(rendered_value)

    def get(self):
        """Handler for latest questions page."""
        query = Question.query(Question.answered > None).order(
                -Question.answered)
        self.render_response('latest.html', questions=query.fetch(20))

APPLICATION = webapp2.WSGIApplication([
        ('/', LatestHandler),
        ('/_ah/xmpp/message/chat/', XmppHandler),
        ('/_ah/xmpp/presence/(available|unavailable)/', XmppPresenceHandler),
        ], debug=True)
<commit_msg>Fixing small syntax error.<commit_after># Copyright 2009 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Crowdguru sample application using the XMPP service on Google App Engine."""

import datetime

from google.appengine.api import datastore_types
from google.appengine.api import xmpp
from google.appengine.datastore import entity_pb
from google.appengine.ext import ndb
from google.appengine.ext.webapp import xmpp_handlers
import webapp2
from webapp2_extras import jinja2

PONDER_MSG = 'Hmm. Let me think on that a bit.'
TELLME_MSG = 'While I\'m thinking, perhaps you can answer me this: {}'
SOMEONE_ANSWERED_MSG = ('We seek those who are wise and fast. One out of two '
                        'is not enough. Another has answered my question.')
ANSWER_INTRO_MSG = 'You asked me: {}'
ANSWER_MSG = 'I have thought long and hard, and concluded: {}'
WAIT_MSG = ('Please! One question at a time! You can ask me another once you '
            'have an answer to your current question.')
THANKS_MSG = 'Thank you for your wisdom.'
TELLME_THANKS_MSG = THANKS_MSG + ' I\'m still thinking about your question.'
EMPTYQ_MSG = 'Sorry, I don\'t have anything to ask you at the moment.'
HELP_MSG = ('I am the amazing Crowd Guru. Ask me a question by typing '
            '\'/tellme the meaning of life\', and I will answer you forthwith! '
            'To learn more, go to {}/')
MAX_ANSWER_TIME = 120

# TODO(dhermes): Get this into NDB.
# http://code.google.com/p/appengine-ndb-experiment/issues/detail?id=235
class IMProperty(ndb.Property):
    """A custom property for handling IM objects."""

    def _validate(self, value):
        """Validator to make sure value is an instance of datastore_types.IM.

        Args:
            value: The value to be validated. Should be an instance of
                datastore_types.IM.

        Raises:
            TypeError: If value is not an instance of datastore_types.IM.
        """
        if not isinstance(value, datastore_types.IM):
            raise TypeError('expected an IM, got {!r}'.format(value))

    def _db_set_value(self, v, p, value):
        """Method to customize the way the entity is sent to the datastore.

        Sets the entity meaning to GD_IM and sets the string value to the string
        value of the IM object. The constructor for IM is written in such a way
        that IM(str(im_value)) == im_value and str_value == str(IM(str_value)).

        Args:
            v: Mutable value of Property Message object.
            p: A Property Message object (a protocol buffer).
            value: The value currently set for the IMProperty.
        """
        v.set_stringvalue(str(value))
        p.set_meaning(entity_pb.Property.GD_IM)

    def _db_get_value(self, v, p):
        """Method to customize the way the entity is built from the datastore.

        Args:
            v: Immutable value of Property Message object.
            p: A Property Message object (a protocol buffer).

        Returns:
            A datastore_types.IM instance built from the string in the
                datastore, unless no string was stored, then returns None.

        Raises:
            ValueError: If the stored entity meaning is not GD_IM.
        """
        if not v.has_stringvalue():
            return None
        meaning = p.meaning()
        if meaning != entity_pb.Property.GD_IM:
            raise ValueError('Value stored not an IM.')
        return datastore_types.IM(v.stringvalue())

class Question(ndb.Model):
    """Model to hold questions that the Guru can answer."""
    question = ndb.TextProperty(required=True)
    asker = IMProperty(required=True)
    asked = ndb.DateTimeProperty(required=True, auto_now_add=True)
    suspended = ndb.BooleanProperty(required=True)

    assignees = IMProperty(repeated=True)
    last_assigned = ndb.DateTimeProperty()

    answer = ndb.TextProperty(indexed=True)
    answerer = IMProperty()
    answered = ndb.DateTimeProperty()

    @staticmethod
    @ndb.transactional
    def _try_assign(key, user, expiry):
        """Assigns and returns the question if it's not assigned already.

        Args:
            key: ndb.Key: The key of a Question to try and assign.
            user: datastore_types.IM: The user to assign the question to.
            expiry: datetime.datetime: The expiry date of the question.

        Returns:
            The Question object. If it was already assigned, no change is made.
        """
        question = key.get()
        if not question.last_assigned or question.last_assigned < expiry:
            question.assignees.append(user)
            question.last_assigned = datetime.datetime.now()
            question.put()
        return question

    @classmethod
    def assign_question(cls, user):
        """Gets an unanswered question and assigns it to a user to answer.

        Args:
            user: datastore_types.IM: The identity of the user to assign a
                question to.

        Returns:
            The Question entity assigned to the user, or None if there are no
                unanswered questions.
        """
        question = None
        while question is None or user not in question.assignees:
            # Assignments made before this timestamp have expired.
            expiry = (datetime.datetime.now()
                      - datetime.timedelta(seconds=MAX_ANSWER_TIME))

            # Find a candidate question
            query = cls.query(cls.answerer == None, cls.last_assigned < expiry)
            # If a question has never been assigned, order by when it was asked
            query = query.order(cls.last_assigned, cls.asked)
            candidates = [candidate for candidate in query.fetch(2)
                          if candidate.asker != user]
            if not candidates:
                # No valid questions in queue.
                break

            # Try and assign it
            question = cls._try_assign(candidates[0].key, user, expiry)

        # Expire the assignment after a couple of minutes
        return question

    @ndb.transactional
    def unassign(self, user):
        """Unassigns the given user from this question.

        Args:
            user: datastore_types.IM: The user who will no longer be answering
                this question.
        """
        question = self.key.get()
        if user in question.assignees:
            question.assignees.remove(user)
            question.put()

    @classmethod
    def get_asked(cls, user):
        """Returns the user's outstanding asked question, if any.

        Args:
            user: datastore_types.IM: The identity of the user asking.

        Returns:
            An unanswered Question entity asked by the user, or None if there
                are no unanswered questions.
        """
        query = cls.query(cls.asker == user, cls.answer == None)
        return query.get()

    @classmethod
    def get_answering(cls, user):
        """Returns the question the user is answering, if any.

        Args:
            user: datastore_types.IM: The identity of the user answering.

        Returns:
            An unanswered Question entity assigned to the user, or None if there
                are no unanswered questions.
        """
        query = cls.query(cls.assignees == user, cls.answer == None)
        return query.get()

def bare_jid(sender):
    """Identify the user by bare jid.

    See http://wiki.xmpp.org/web/Jabber_Resources for more details.

    Args:
        sender: String; A jabber or XMPP sender.

    Returns:
        The bare Jabber ID of the sender.
    """
    return sender.split('/')[0]

class XmppHandler(xmpp_handlers.CommandHandler):
    """Handler class for all XMPP activity."""

    def unhandled_command(self, message=None):
        """Shows help text for commands which have no handler.

        Args:
            message: xmpp.Message: The message that was sent by the user.
        """
        message.reply(HELP_MSG.format(self.request.host_url))

    def askme_command(self, message=None):
        """Responds to the /askme command.

        Args:
            message: xmpp.Message: The message that was sent by the user.
        """
        im_from = datastore_types.IM('xmpp', bare_jid(message.sender))
        currently_answering = Question.get_answering(im_from)
        question = Question.assign_question(im_from)
        if question:
            message.reply(TELLME_MSG.format(question.question))
        else:
            message.reply(EMPTYQ_MSG)
        # Don't unassign their current question until we've picked a new one.
        if currently_answering:
            currently_answering.unassign(im_from)

    def text_message(self, message=None):
        """Called when a message not prefixed by a /cmd is sent to the XMPP bot.

        Args:
            message: xmpp.Message: The message that was sent by the user.
        """
        im_from = datastore_types.IM('xmpp', bare_jid(message.sender))
        question = Question.get_answering(im_from)
        if question:
            other_assignees = question.assignees
            other_assignees.remove(im_from)

            # Answering a question
            question.answer = message.arg
            question.answerer = im_from
            question.assignees = []
            question.answered = datetime.datetime.now()
            question.put()

            # Send the answer to the asker
            xmpp.send_message([question.asker.address],
                              ANSWER_INTRO_MSG.format(question.question))
            xmpp.send_message([question.asker.address],
                              ANSWER_MSG.format(message.arg))

            # Send acknowledgement to the answerer
            asked_question = Question.get_asked(im_from)
            if asked_question:
                message.reply(TELLME_THANKS_MSG)
            else:
                message.reply(THANKS_MSG)

            # Tell any other assignees their help is no longer required
            if other_assignees:
                xmpp.send_message([user.address for user in other_assignees],
                                  SOMEONE_ANSWERED_MSG)
        else:
            self.unhandled_command(message)

    def tellme_command(self, message=None):
        """Handles /tellme requests, asking the Guru a question.

        Args:
            message: xmpp.Message: The message that was sent by the user.
        """
        im_from = datastore_types.IM('xmpp', bare_jid(message.sender))
        asked_question = Question.get_asked(im_from)

        if asked_question:
            # Already have a question
            message.reply(WAIT_MSG)
        else:
            # Asking a question
            asked_question = Question(question=message.arg, asker=im_from)
            asked_question.put()

            currently_answering = Question.get_answering(im_from)
            if not currently_answering:
                # Try and find one for them to answer
                question = Question.assign_question(im_from)
                if question:
                    message.reply(TELLME_MSG.format(question.question))
                    return
            message.reply(PONDER_MSG)

class XmppPresenceHandler(webapp2.RequestHandler):
    """Handler class for XMPP status updates."""

    def post(self, status):
        """POST handler for XMPP presence.

        Args:
            status: A string which will be either available or unavailable
               and will indicate the status of the user.
        """
        sender = self.request.get('from')
        im_from = datastore_types.IM('xmpp', bare_jid(sender))
        suspend = (status == 'unavailable')
        query = Question.filter(Question.asker == im_from,
                                Question.answer == None,
                                Question.suspended == (not suspend))
        question = query.get()
        if question:
            question.suspended = suspend
            question.put()

class LatestHandler(webapp2.RequestHandler):
    """Displays the most recently answered questions."""

    @webapp2.cached_property
    def jinja2(self):
        """Cached property holding a Jinja2 instance.

        Returns:
            A Jinja2 object for the current app.
        """
        return jinja2.get_jinja2(app=self.app)

    def render_response(self, template, **context):
        """Use Jinja2 instance to render template and write to output.

        Args:
            template: filename (relative to $PROJECT/templates) that we are
                rendering.
            context: keyword arguments corresponding to variables in template.
        """
        rendered_value = self.jinja2.render_template(template, **context)
        self.response.write(rendered_value)

    def get(self):
        """Handler for latest questions page."""
        query = Question.query(Question.answered > None).order(
                -Question.answered)
        self.render_response('latest.html', questions=query.fetch(20))

APPLICATION = webapp2.WSGIApplication([
        ('/', LatestHandler),
        ('/_ah/xmpp/message/chat/', XmppHandler),
        ('/_ah/xmpp/presence/(available|unavailable)/', XmppPresenceHandler),
        ], debug=True)
<|endoftext|>


<commit_before>from crontab import *
from ee.core.logging import Log

"""
Set CRON on LINUX system.
"""

class EECron():
    def setcron_daily(self,cmd,comment='Cron set by EasyEngine',user='root',min=0,hour=12):
        tab = CronTab(user=user)
        cron_job = tab.new(cmd, comment=comment)
        cron_job.minute().on(min)
        cron_job.hour().on(hour)
        #writes to crontab
        tab.write()
        Log.debug(self, "Cron is set:\n" + tab.render())
<commit_msg>added check_isexist function<commit_after>from crontab import *
from ee.core.shellexec import EEShellExec
from ee.core.logging import Log

"""
Set CRON on LINUX system.
"""

class EECron():
    def setcron_daily(self,cmd,comment='Cron set by EasyEngine',user='root',min=0,hour=12):
        if not self.check_isexist(self,cmd):
            tab = CronTab(user=user)
            cron_job = tab.new(cmd, comment=comment)
            cron_job.minute().on(min)
            cron_job.hour().on(hour)
            #writes to crontab
            tab.write()
            Log.debug(self, "Cron is set:\n" + tab.render())

    #Check if cron already exist
    def check_isexist(self,cmd):

         if EEShellExec.cmd_exec(self, "crontab -l | grep -q \'{0}\'".format(cmd)):
             Log.debug(self, "Cron already exist")
             return True
         else:
             return False<|endoftext|>


<commit_before># Copyright 2009 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import datetime

from google.appengine.api import xmpp
from google.appengine.ext import db
from google.appengine.ext.webapp import xmpp_handlers
import webapp2
from webapp2_extras import jinja2

PONDER_MSG = 'Hmm. Let me think on that a bit.'
TELLME_MSG = 'While I\'m thinking, perhaps you can answer me this: %s'
SOMEONE_ANSWERED_MSG = ('We seek those who are wise and fast. One out of two '
                        'is not enough. Another has answered my question.')
ANSWER_INTRO_MSG = 'You asked me: %s'
ANSWER_MSG = 'I have thought long and hard, and concluded: %s'
WAIT_MSG = ('Please! One question at a time! You can ask me another once you '
            'have an answer to your current question.')
THANKS_MSG = 'Thank you for your wisdom.'
TELLME_THANKS_MSG = ('Thank you for your wisdom.'
                     ' I\'m still thinking about your question.')
EMPTYQ_MSG = 'Sorry, I don\'t have anything to ask you at the moment.'
HELP_MSG = ('I am the amazing Crowd Guru. Ask me a question by typing '
            '\'/tellme the meaning of life\', and I will answer you forthwith! '
            'To learn more, go to %s/')
MAX_ANSWER_TIME = 120

class Question(db.Model):
  question = db.TextProperty(required=True)
  asker = db.IMProperty(required=True)
  asked = db.DateTimeProperty(required=True, auto_now_add=True)

  assignees = db.ListProperty(db.IM)
  last_assigned = db.DateTimeProperty()

  answer = db.TextProperty()
  answerer = db.IMProperty()
  answered = db.DateTimeProperty()

  @staticmethod
  def _tryAssignTx(key, user, expiry):
    """Assigns and returns the question if it's not assigned already.

    Args:
      key: db.Key: The key of a Question to try and assign.
      user: db.IM: The user to assign the question to.
    Returns:
      The Question object. If it was already assigned, no change is made
    """
    question = Question.get(key)
    if not question.last_assigned or question.last_assigned < expiry:
      question.assignees.append(user)
      question.last_assigned = datetime.datetime.now()
      question.put()
    return question

  @staticmethod
  def assignQuestion(user):
    """Gets an unanswered question and assigns it to a user to answer.

    Args:
      user: db.IM: The identity of the user to assign a question to.
    Returns:
      The Question entity assigned to the user, or None if there are no
        unanswered questions.
    """
    question = None
    while question == None or user not in question.assignees:
      # Assignments made before this timestamp have expired.
      expiry = (datetime.datetime.now()
                - datetime.timedelta(seconds=MAX_ANSWER_TIME))

      # Find a candidate question
      query = Question.all()
      query.filter('answerer =', None)
      query.filter('last_assigned <', expiry).order('last_assigned')
      # If a question has never been assigned, order by when it was asked
      query.order('asked')
      candidates = [candidate for candidate in query.fetch(2)
                    if candidate.asker != user]
      if not candidates:
        # No valid questions in queue.
        break

      # Try and assign it
      question = db.run_in_transaction(Question._tryAssignTx,
                                       candidates[0].key(), user, expiry)

    # Expire the assignment after a couple of minutes
    return question

  def _unassignTx(self, user):
    question = Question.get(self.key())
    if user in question.assignees:
      question.assignees.remove(user)
      question.put()

  def unassign(self, user):
    """Unassigns the given user to this question.

    Args:
      user: db.IM: The user who will no longer be answering this question.
    """
    db.run_in_transaction(self._unassignTx, user)

class XmppHandler(xmpp_handlers.CommandHandler):
  """Handler class for all XMPP activity."""

  def _GetAsked(self, user):
    """Returns the user's outstanding asked question, if any."""
    query = Question.all()
    query.filter('asker =', user)
    query.filter('answer =', None)
    return query.get()

  def _GetAnswering(self, user):
    """Returns the question the user is answering, if any."""
    query = Question.all()
    query.filter('assignees =', user)
    query.filter('answer =', None)
    return query.get()

  def unhandled_command(self, message=None):
    # Show help text
    message.reply(HELP_MSG % (self.request.host_url,))

  def askme_command(self, message=None):
    im_from = db.IM('xmpp', message.sender)
    currently_answering = self._GetAnswering(im_from)
    question = Question.assignQuestion(im_from)
    if question:
      message.reply(TELLME_MSG % (question.question,))
    else:
      message.reply(EMPTYQ_MSG)
    # Don't unassign their current question until we've picked a new one.
    if currently_answering:
      currently_answering.unassign(im_from)

  def text_message(self, message=None):
    im_from = db.IM('xmpp', message.sender)
    question = self._GetAnswering(im_from)
    if question:
      other_assignees = question.assignees
      other_assignees.remove(im_from)

      # Answering a question
      question.answer = message.arg
      question.answerer = im_from
      question.assignees = []
      question.answered = datetime.datetime.now()
      question.put()

      # Send the answer to the asker
      xmpp.send_message([question.asker.address],
                        ANSWER_INTRO_MSG % (question.question,))
      xmpp.send_message([question.asker.address], ANSWER_MSG % (message.arg,))

      # Send acknowledgement to the answerer
      asked_question = self._GetAsked(im_from)
      if asked_question:
        message.reply(TELLME_THANKS_MSG)
      else:
        message.reply(THANKS_MSG)

      # Tell any other assignees their help is no longer required
      if other_assignees:
        xmpp.send_message([x.address for x in other_assignees],
                          SOMEONE_ANSWERED_MSG)
    else:
      self.unhandled_command(message)

  def tellme_command(self, message=None):
    im_from = db.IM('xmpp', message.sender)
    asked_question = self._GetAsked(im_from)
    currently_answering = self._GetAnswering(im_from)

    if asked_question:
      # Already have a question
      message.reply(WAIT_MSG)
    else:
      # Asking a question
      asked_question = Question(question=message.arg, asker=im_from)
      asked_question.put()

      if not currently_answering:
        # Try and find one for them to answer
        question = Question.assignQuestion(im_from)
        if question:
          message.reply(TELLME_MSG % (question.question,))
          return
      message.reply(PONDER_MSG)

class LatestHandler(webapp2.RequestHandler):
  """Displays the most recently answered questions."""

  @webapp2.cached_property
  def Jinja2(self):
    """Cached property holding a Jinja2 instance."""
    return jinja2.get_jinja2(app=self.app)

  def RenderResponse(self, template, **context):
    """Use Jinja2 instance to render template and write to output.

    Args:
      template: filename (relative to $PROJECT/templates) that we are rendering
      context: keyword arguments corresponding to variables in template
    """
    rendered_value = self.Jinja2.render_template(template, **context)
    self.response.write(rendered_value)

  def get(self):
    query = Question.all().order('-answered').filter('answered >', None)
    self.RenderResponse('latest.html', questions=query.fetch(20))

application = webapp2.WSGIApplication([
    ('/', LatestHandler),
    ('/_ah/xmpp/message/chat/', XmppHandler),
    ], debug=True)
<commit_msg>Updating to NDB and fixing more style guide type stuff.<commit_after># Copyright 2009 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import datetime

from google.appengine.api import datastore_types
from google.appengine.api import xmpp
from google.appengine.ext import ndb
from google.appengine.ext.webapp import xmpp_handlers
import webapp2
from webapp2_extras import jinja2

PONDER_MSG = 'Hmm. Let me think on that a bit.'
TELLME_MSG = 'While I\'m thinking, perhaps you can answer me this: {}'
SOMEONE_ANSWERED_MSG = ('We seek those who are wise and fast. One out of two '
                        'is not enough. Another has answered my question.')
ANSWER_INTRO_MSG = 'You asked me: {}'
ANSWER_MSG = 'I have thought long and hard, and concluded: {}'
WAIT_MSG = ('Please! One question at a time! You can ask me another once you '
            'have an answer to your current question.')
THANKS_MSG = 'Thank you for your wisdom.'
TELLME_THANKS_MSG = THANKS_MSG + ' I\'m still thinking about your question.'
EMPTYQ_MSG = 'Sorry, I don\'t have anything to ask you at the moment.'
HELP_MSG = ('I am the amazing Crowd Guru. Ask me a question by typing '
            '\'/tellme the meaning of life\', and I will answer you forthwith! '
            'To learn more, go to {}/')
MAX_ANSWER_TIME = 120

class IMProperty(ndb.PickleProperty):
  """A custom property for handling IM objects."""

  def _validate(self, value):
    """Validator to make sure the value is an instance of datastore_types.IM.

    Args:
      value: The value to be validated. Shoudl be an instance of
        datastore_types.IM.

    Raises:
      TypeError: If value is not an instance of datastore_types.IM.
    """
    if not isinstance(value, datastore_types.IM):
      raise TypeError('expected an IM, got {!r}'.format(value))

class Question(ndb.Model):
  """Model to hold questions that the Guru can answer."""
  question = ndb.TextProperty(required=True)
  asker = IMProperty(required=True, indexed=True)
  asked = ndb.DateTimeProperty(required=True, auto_now_add=True)

  assignees = IMProperty(repeated=True, indexed=True)
  last_assigned = ndb.DateTimeProperty()

  answer = ndb.TextProperty(indexed=True)
  answerer = IMProperty(indexed=True)
  answered = ndb.DateTimeProperty()

  @classmethod
  def AssignQuestion(cls, user):
    """Gets an unanswered question and assigns it to a user to answer.

    Args:
      user: datastore_types.IM: The identity of the user to assign a
        question to.

    Returns:
      The Question entity assigned to the user, or None if there are no
        unanswered questions.
    """
    question = None
    while question is None or user not in question.assignees:
      # Assignments made before this timestamp have expired.
      expiry = (datetime.datetime.now()
                - datetime.timedelta(seconds=MAX_ANSWER_TIME))

      # Find a candidate question
      query = cls.query(cls.answerer == None, cls.last_assigned < expiry)
      # If a question has never been assigned, order by when it was asked
      query = query.order(cls.last_assigned, cls.asked)
      candidates = [candidate for candidate in query.fetch(2)
                    if candidate.asker != user]
      if not candidates:
        # No valid questions in queue.
        break

      # Try and assign it
      candidate = candidates[0]
      question = _TryAssign(candidate.key, user, expiry)

    # Expire the assignment after a couple of minutes
    return question

  @ndb.transactional
  def Unassign(self, user):
    """Unassigns the given user from this question.

    Args:
      user: datastore_types.IM: The user who will no longer be answering this
        question.
    """
    question = self.key.get()
    if user in question.assignees:
      question.assignees.remove(user)
      question.put()

@ndb.transactional
def _TryAssign(key, user, expiry):
  """Assigns and returns the question if it's not assigned already.

  Args:
    key: ndb.Key: The key of a Question to try and assign.
    user: datastore_types.IM: The user to assign the question to.
    expiry: datetime.datetime: The expiry date of the question.

  Returns:
    The Question object. If it was already assigned, no change is made.
  """
  question = key.get()
  if not question.last_assigned or question.last_assigned < expiry:
    question.assignees.append(user)
    question.last_assigned = datetime.datetime.now()
    question.put()
  return question

class XmppHandler(xmpp_handlers.CommandHandler):
  """Handler class for all XMPP activity."""

  def _GetAsked(self, user):
    """Returns the user's outstanding asked question, if any.

    Args:
      user: datastore_types.IM: The identity of the user asking.

    Returns:
      An unanswered Question entity asked by the user, or None if there are no
        unanswered questions.
    """
    query = Question.query(Question.asker == user, Question.answer == None)
    return query.get()

  def _GetAnswering(self, user):
    """Returns the question the user is answering, if any.

    Args:
      user: datastore_types.IM: The identity of the user answering.

    Returns:
      An unanswered Question entity assigned to the user, or None if there are
        no unanswered questions.
    """
    query = Question.query(Question.assignees == user, Question.answer == None)
    return query.get()

  def unhandled_command(self, message=None):
    """Shows help text for commands which have no handler.

    Args:
      message: xmpp.Message: The message that was sent by the user.
    """
    message.reply(HELP_MSG.format(self.request.host_url))

  def askme_command(self, message=None):
    """Responds to the /askme command.

    Args:
      message: xmpp.Message: The message that was sent by the user.
    """
    im_from = datastore_types.IM('xmpp', message.sender)
    currently_answering = self._GetAnswering(im_from)
    question = Question.AssignQuestion(im_from)
    if question:
      message.reply(TELLME_MSG.format(question.question))
    else:
      message.reply(EMPTYQ_MSG)
    # Don't unassign their current question until we've picked a new one.
    if currently_answering:
      currently_answering.Unassign(im_from)

  def text_message(self, message=None):
    """Called when a message not prefixed by a /command is sent to the XMPP bot.

    Args:
      message: xmpp.Message: The message that was sent by the user.
    """
    im_from = datastore_types.IM('xmpp', message.sender)
    question = self._GetAnswering(im_from)
    if question:
      other_assignees = question.assignees
      other_assignees.remove(im_from)

      # Answering a question
      question.answer = message.arg
      question.answerer = im_from
      question.assignees = []
      question.answered = datetime.datetime.now()
      question.put()

      # Send the answer to the asker
      xmpp.send_message([question.asker.address],
                        ANSWER_INTRO_MSG.format(question.question))
      xmpp.send_message([question.asker.address],
                        ANSWER_MSG.format(message.arg))

      # Send acknowledgement to the answerer
      asked_question = self._GetAsked(im_from)
      if asked_question:
        message.reply(TELLME_THANKS_MSG)
      else:
        message.reply(THANKS_MSG)

      # Tell any other assignees their help is no longer required
      if other_assignees:
        xmpp.send_message([user.address for user in other_assignees],
                          SOMEONE_ANSWERED_MSG)
    else:
      self.unhandled_command(message)

  def tellme_command(self, message=None):
    """Responds to the /tellme command.

    Args:
      message: xmpp.Message: The message that was sent by the user.
    """
    im_from = datastore_types.IM('xmpp', message.sender)
    asked_question = self._GetAsked(im_from)

    if asked_question:
      # Already have a question
      message.reply(WAIT_MSG)
    else:
      # Asking a question
      asked_question = Question(question=message.arg, asker=im_from)
      asked_question.put()

      currently_answering = self._GetAnswering(im_from)
      if not currently_answering:
        # Try and find one for them to answer
        question = Question.AssignQuestion(im_from)
        if question:
          message.reply(TELLME_MSG.format(question.question))
          return
      message.reply(PONDER_MSG)

class LatestHandler(webapp2.RequestHandler):
  """Displays the most recently answered questions."""

  @webapp2.cached_property
  def Jinja2(self):
    """Cached property holding a Jinja2 instance."""
    return jinja2.get_jinja2(app=self.app)

  def RenderResponse(self, template, **context):
    """Use Jinja2 instance to render template and write to output.

    Args:
      template: filename (relative to $PROJECT/templates) that we are rendering
      context: keyword arguments corresponding to variables in template
    """
    rendered_value = self.Jinja2.render_template(template, **context)
    self.response.write(rendered_value)

  def get(self):
    """Handler for latest questions page."""
    query = Question.query(Question.answered > None).order(-Question.answered)
    self.RenderResponse('latest.html', questions=query.fetch(20))

application = webapp2.WSGIApplication([
    ('/', LatestHandler),
    ('/_ah/xmpp/message/chat/', XmppHandler),
    ], debug=True)
<|endoftext|>