package tsi1

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"hash/crc32"
	"io"
	"os"
	"sort"
	"sync"
	"time"
	"unsafe"

	"github.com/influxdata/platform/models"
	"github.com/influxdata/platform/pkg/bloom"
	"github.com/influxdata/platform/pkg/mmap"
	"github.com/influxdata/platform/tsdb"
)

// Log errors.
var (
	ErrLogEntryChecksumMismatch = errors.New("log entry checksum mismatch")
)

// Log entry flag constants.
const (
	LogEntrySeriesTombstoneFlag      = 0x01
	LogEntryMeasurementTombstoneFlag = 0x02
	LogEntryTagKeyTombstoneFlag      = 0x04
	LogEntryTagValueTombstoneFlag    = 0x08
)

// defaultLogFileBufferSize describes the size of the buffer that the LogFile's buffered
// writer uses. If the LogFile does not have an explicit buffer size set then
// this is the size of the buffer; it is equal to the default buffer size used
// by a bufio.Writer.
const defaultLogFileBufferSize = 4096

// indexFileBufferSize is the buffer size used when compacting the LogFile down
// into a .tsi file.
const indexFileBufferSize = 1 << 17 // 128K

// LogFile represents an on-disk write-ahead log file.
type LogFile struct {
	mu         sync.RWMutex
	wg         sync.WaitGroup // ref count
	id         int            // file sequence identifier
	data       []byte         // mmap
	file       *os.File       // writer
	w          *bufio.Writer  // buffered writer
	bufferSize int            // The size of the buffer used by the buffered writer
	nosync     bool           // Disables buffer flushing and file syncing. Useful for offline tooling.
	buf        []byte         // marshaling buffer
	keyBuf     []byte

	sfile   *tsdb.SeriesFile // series lookup
	size    int64            // tracks current file size
	modTime time.Time        // tracks last time write occurred

	// In-memory series existence/tombstone sets.
	seriesIDSet, tombstoneSeriesIDSet *tsdb.SeriesIDSet

	// In-memory index.
	mms logMeasurements

	// In-memory stats
	stats MeasurementCardinalityStats

	// Filepath to the log file.
	path string
}

// NewLogFile returns a new instance of LogFile.
func NewLogFile(sfile *tsdb.SeriesFile, path string) *LogFile {
	return &LogFile{
		sfile: sfile,
		path:  path,
		mms:   make(logMeasurements),
		stats: make(MeasurementCardinalityStats),

		seriesIDSet:          tsdb.NewSeriesIDSet(),
		tombstoneSeriesIDSet: tsdb.NewSeriesIDSet(),
	}
}

// bytes estimates the memory footprint of this LogFile, in bytes.
func (f *LogFile) bytes() int {
	var b int
	b += 24 // mu RWMutex is 24 bytes
	b += 16 // wg WaitGroup is 16 bytes
	b += int(unsafe.Sizeof(f.id))
	// Do not include f.data because it is mmap'd
	// TODO(jacobmarble): Uncomment when we are using go >= 1.10.0
	//b += int(unsafe.Sizeof(f.w)) + f.w.Size()
	b += int(unsafe.Sizeof(f.buf)) + len(f.buf)
	b += int(unsafe.Sizeof(f.keyBuf)) + len(f.keyBuf)
	// Do not count SeriesFile because it belongs to the code that constructed this Index.
	b += int(unsafe.Sizeof(f.size))
	b += int(unsafe.Sizeof(f.modTime))
	b += int(unsafe.Sizeof(f.seriesIDSet)) + f.seriesIDSet.Bytes()
	b += int(unsafe.Sizeof(f.tombstoneSeriesIDSet)) + f.tombstoneSeriesIDSet.Bytes()
	b += int(unsafe.Sizeof(f.mms)) + f.mms.bytes()
	b += int(unsafe.Sizeof(f.path)) + len(f.path)
	return b
}

// Open reads the log from a file and validates all the checksums.
func (f *LogFile) Open() error {
	if err := f.open(); err != nil {
		f.Close()
		return err
	}
	return nil
}

func (f *LogFile) open() error {
	f.id, _ = ParseFilename(f.path)

	// Open file for appending.
	file, err := os.OpenFile(f.Path(), os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return err
	}
	f.file = file

	if f.bufferSize == 0 {
		f.bufferSize = defaultLogFileBufferSize
	}
	f.w = bufio.NewWriterSize(f.file, f.bufferSize)

	// Finish opening if file is empty.
	fi, err := file.Stat()
	if err != nil {
		return err
	} else if fi.Size() == 0 {
		return nil
	}
	f.size = fi.Size()
	f.modTime = fi.ModTime()

	// Open a read-only memory map of the existing data.
	data, err := mmap.Map(f.Path(), 0)
	if err != nil {
		return err
	}
	f.data = data

	// Read log entries from mmap.
	var n int64
	for buf := f.data; len(buf) > 0; {
		// Read next entry. Truncate partial writes.
		var e LogEntry
		if err := e.UnmarshalBinary(buf); err == io.ErrShortBuffer || err == ErrLogEntryChecksumMismatch {
			break
		} else if err != nil {
			return err
		}

		// Execute entry against in-memory index.
		f.execEntry(&e)

		// Move buffer forward.
		n += int64(e.Size)
		buf = buf[e.Size:]
	}

	// Move to the end of the file.
	f.size = n
	_, err = file.Seek(n, io.SeekStart)
	return err
}

// Close shuts down the file handle and mmap.
func (f *LogFile) Close() error {
	// Wait until the file has no more references.
	f.wg.Wait()

	if f.w != nil {
		f.w.Flush()
		f.w = nil
	}

	if f.file != nil {
		f.file.Close()
		f.file = nil
	}

	if f.data != nil {
		mmap.Unmap(f.data)
	}

	f.mms = make(logMeasurements)
	return nil
}

// FlushAndSync flushes buffered data to disk and then fsyncs the underlying file.
// If the LogFile has disabled flushing and syncing then FlushAndSync is a no-op.
func (f *LogFile) FlushAndSync() error {
	if f.nosync {
		return nil
	}

	if f.w != nil {
		if err := f.w.Flush(); err != nil {
			return err
		}
	}

	if f.file == nil {
		return nil
	}
	return f.file.Sync()
}

// ID returns the file sequence identifier.
func (f *LogFile) ID() int { return f.id }

// Path returns the file path.
func (f *LogFile) Path() string { return f.path }

// SetPath sets the log file's path.
func (f *LogFile) SetPath(path string) { f.path = path }

// Level returns the log level of the file.
func (f *LogFile) Level() int { return 0 }

// Filter returns the bloom filter for the file.
func (f *LogFile) Filter() *bloom.Filter { return nil }

// Retain adds a reference count to the file.
func (f *LogFile) Retain() { f.wg.Add(1) }

// Release removes a reference count from the file.
func (f *LogFile) Release() { f.wg.Done() }

// Stat returns size and last modification time of the file.
func (f *LogFile) Stat() (int64, time.Time) {
	f.mu.RLock()
	size, modTime := f.size, f.modTime
	f.mu.RUnlock()
	return size, modTime
}

// SeriesIDSet returns the series existence set.
func (f *LogFile) SeriesIDSet() (*tsdb.SeriesIDSet, error) {
	return f.seriesIDSet, nil
}

// TombstoneSeriesIDSet returns the series tombstone set.
func (f *LogFile) TombstoneSeriesIDSet() (*tsdb.SeriesIDSet, error) {
	return f.tombstoneSeriesIDSet, nil
}

// Size returns the size of the file, in bytes.
func (f *LogFile) Size() int64 {
	f.mu.RLock()
	v := f.size
	f.mu.RUnlock()
	return v
}

// Measurement returns a measurement element.
func (f *LogFile) Measurement(name []byte) MeasurementElem {
	f.mu.RLock()
	defer f.mu.RUnlock()

	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}

	return mm
}

func (f *LogFile) MeasurementHasSeries(ss *tsdb.SeriesIDSet, name []byte) bool {
	f.mu.RLock()
	defer f.mu.RUnlock()

	mm, ok := f.mms[string(name)]
	if !ok {
		return false
	}

	// TODO(edd): if mm is using a seriesSet then this could be changed to do a fast intersection.
	for _, id := range mm.seriesIDs() {
		if ss.Contains(id) {
			return true
		}
	}
	return false
}

// MeasurementNames returns an ordered list of measurement names.
func (f *LogFile) MeasurementNames() []string {
	f.mu.RLock()
	defer f.mu.RUnlock()
	return f.measurementNames()
}

func (f *LogFile) measurementNames() []string {
	a := make([]string, 0, len(f.mms))
	for name := range f.mms {
		a = append(a, name)
	}
	sort.Strings(a)
	return a
}

// DeleteMeasurement adds a tombstone for a measurement to the log file.
func (f *LogFile) DeleteMeasurement(name []byte) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	e := LogEntry{Flag: LogEntryMeasurementTombstoneFlag, Name: name}
	if err := f.appendEntry(&e); err != nil {
		return err
	}
	f.execEntry(&e)

	// Flush buffer and sync to disk.
	return f.FlushAndSync()
}

// TagKeySeriesIDIterator returns a series iterator for a tag key.
func (f *LogFile) TagKeySeriesIDIterator(name, key []byte) tsdb.SeriesIDIterator {
	f.mu.RLock()
	defer f.mu.RUnlock()

	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}

	tk, ok := mm.tagSet[string(key)]
	if !ok {
		return nil
	}

	// Combine iterators across all tag keys.
	itrs := make([]tsdb.SeriesIDIterator, 0, len(tk.tagValues))
	for _, tv := range tk.tagValues {
		if tv.cardinality() == 0 {
			continue
		}
		itrs = append(itrs, tsdb.NewSeriesIDSetIterator(tv.seriesIDSet()))
	}

	return tsdb.MergeSeriesIDIterators(itrs...)
}

// TagKeyIterator returns a value iterator for a measurement.
func (f *LogFile) TagKeyIterator(name []byte) TagKeyIterator {
	f.mu.RLock()
	defer f.mu.RUnlock()

	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}

	a := make([]logTagKey, 0, len(mm.tagSet))
	for _, k := range mm.tagSet {
		a = append(a, k)
	}
	return newLogTagKeyIterator(a)
}

// TagKey returns a tag key element.
func (f *LogFile) TagKey(name, key []byte) TagKeyElem {
	f.mu.RLock()
	defer f.mu.RUnlock()

	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}

	tk, ok := mm.tagSet[string(key)]
	if !ok {
		return nil
	}

	return &tk
}

// TagValue returns a tag value element.
func (f *LogFile) TagValue(name, key, value []byte) TagValueElem {
	f.mu.RLock()
	defer f.mu.RUnlock()

	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}

	tk, ok := mm.tagSet[string(key)]
	if !ok {
		return nil
	}

	tv, ok := tk.tagValues[string(value)]
	if !ok {
		return nil
	}

	return &tv
}

// TagValueIterator returns a value iterator for a tag key.
func (f *LogFile) TagValueIterator(name, key []byte) TagValueIterator {
	f.mu.RLock()
	defer f.mu.RUnlock()

	mm, ok := f.mms[string(name)]
	if !ok {
		return nil
	}

	tk, ok := mm.tagSet[string(key)]
	if !ok {
		return nil
	}
	return tk.TagValueIterator()
}

// DeleteTagKey adds a tombstone for a tag key to the log file.
func (f *LogFile) DeleteTagKey(name, key []byte) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	e := LogEntry{Flag: LogEntryTagKeyTombstoneFlag, Name: name, Key: key}
	if err := f.appendEntry(&e); err != nil {
		return err
	}
	f.execEntry(&e)

	// Flush buffer and sync to disk.
	return f.FlushAndSync()
}

// TagValueSeriesIDSet returns a series iterator for a tag value.
func (f *LogFile) TagValueSeriesIDSet(name, key, value []byte) (*tsdb.SeriesIDSet, error) {
	f.mu.RLock()
	defer f.mu.RUnlock()

	mm, ok := f.mms[string(name)]
	if !ok {
		return nil, nil
	}

	tk, ok := mm.tagSet[string(key)]
	if !ok {
		return nil, nil
	}

	tv, ok := tk.tagValues[string(value)]
	if !ok {
		return nil, nil
	} else if tv.cardinality() == 0 {
		return nil, nil
	}

	return tv.seriesIDSet(), nil
}

// MeasurementN returns the total number of measurements.
func (f *LogFile) MeasurementN() (n uint64) {
	f.mu.RLock()
	defer f.mu.RUnlock()
	return uint64(len(f.mms))
}

// TagKeyN returns the total number of keys.
func (f *LogFile) TagKeyN() (n uint64) {
	f.mu.RLock()
	defer f.mu.RUnlock()
	for _, mm := range f.mms {
		n += uint64(len(mm.tagSet))
	}
	return n
}

// TagValueN returns the total number of values.
func (f *LogFile) TagValueN() (n uint64) {
	f.mu.RLock()
	defer f.mu.RUnlock()
	for _, mm := range f.mms {
		for _, k := range mm.tagSet {
			n += uint64(len(k.tagValues))
		}
	}
	return n
}

// DeleteTagValue adds a tombstone for a tag value to the log file.
func (f *LogFile) DeleteTagValue(name, key, value []byte) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	e := LogEntry{Flag: LogEntryTagValueTombstoneFlag, Name: name, Key: key, Value: value}
	if err := f.appendEntry(&e); err != nil {
		return err
	}
	f.execEntry(&e)

	// Flush buffer and sync to disk.
	return f.FlushAndSync()
}

// AddSeriesList adds a list of series to the log file in bulk.
func (f *LogFile) AddSeriesList(seriesSet *tsdb.SeriesIDSet, collection *tsdb.SeriesCollection) ([]tsdb.SeriesID, error) {
	var writeRequired bool
	var entries []LogEntry

	var i int // Track the index of the point in the batch
	seriesSet.RLock()
	for iter := collection.Iterator(); iter.Next(); {
		seriesID := iter.SeriesID()

		if seriesSet.ContainsNoLock(seriesID) {
			i++
			continue
		}
		writeRequired = true

		// lazy allocation of entries to avoid common case of no new series
		if entries == nil {
			entries = make([]LogEntry, 0, collection.Length())
		}

		entries = append(entries, LogEntry{
			SeriesID: seriesID,
			name:     iter.Name(),
			tags:     iter.Tags(),
			cached:   true,
			batchidx: i,
		})
		i++
	}
	seriesSet.RUnlock()

	// Exit if all series already exist.
	if !writeRequired {
		return nil, nil
	}

	f.mu.Lock()
	defer f.mu.Unlock()

	seriesSet.Lock()
	defer seriesSet.Unlock()
	var seriesIDs []tsdb.SeriesID
	for i := range entries { // NB - this doesn't evaluate all series ids returned from series file.
		entry := &entries[i]
		if seriesSet.ContainsNoLock(entry.SeriesID) {
			// We don't need to allocate anything for this series.
			continue
		}
		if err := f.appendEntry(entry); err != nil {
			return nil, err
		}
		f.execEntry(entry)
		seriesSet.AddNoLock(entry.SeriesID)

		if seriesIDs == nil {
			seriesIDs = make([]tsdb.SeriesID, collection.Length())
		}
		seriesIDs[entry.batchidx] = entry.SeriesID
	}

	// Flush buffer and sync to disk.
	if err := f.FlushAndSync(); err != nil {
		return nil, err
	}
	return seriesIDs, nil
}

// DeleteSeriesID adds a tombstone for a series id.
func (f *LogFile) DeleteSeriesID(id tsdb.SeriesID) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	e := LogEntry{Flag: LogEntrySeriesTombstoneFlag, SeriesID: id}
	if err := f.appendEntry(&e); err != nil {
		return err
	}
	f.execEntry(&e)

	// Flush buffer and sync to disk.
	return f.FlushAndSync()
}

// SeriesN returns the total number of series in the file.
func (f *LogFile) SeriesN() (n uint64) {
	f.mu.RLock()
	defer f.mu.RUnlock()

	for _, mm := range f.mms {
		n += uint64(mm.cardinality())
	}
	return n
}

// appendEntry adds a log entry to the end of the file.
func (f *LogFile) appendEntry(e *LogEntry) error {
	// Marshal entry to the local buffer.
	f.buf = appendLogEntry(f.buf[:0], e)

	// Save the size of the record.
	e.Size = len(f.buf)

	// Write record to file.
	n, err := f.w.Write(f.buf)
	if err != nil {
		// Move position backwards over partial entry.
		// Log should be reopened if seeking cannot be completed.
		if n > 0 {
			f.w.Reset(f.file)
			if _, err := f.file.Seek(int64(-n), io.SeekCurrent); err != nil {
				f.Close()
			}
		}
		return err
	}

	// Update in-memory file size & modification time.
	f.size += int64(n)
	f.modTime = time.Now()

	return nil
}

// execEntry executes a log entry against the in-memory index.
// This is done after appending and on replay of the log.
func (f *LogFile) execEntry(e *LogEntry) {
	switch e.Flag {
	case LogEntryMeasurementTombstoneFlag:
		f.execDeleteMeasurementEntry(e)
	case LogEntryTagKeyTombstoneFlag:
		f.execDeleteTagKeyEntry(e)
	case LogEntryTagValueTombstoneFlag:
		f.execDeleteTagValueEntry(e)
	default:
		f.execSeriesEntry(e)
	}
}

func (f *LogFile) execDeleteMeasurementEntry(e *LogEntry) {
	mm := f.createMeasurementIfNotExists(e.Name)
	mm.deleted = true
	mm.tagSet = make(map[string]logTagKey)
	mm.series = make(map[tsdb.SeriesID]struct{})
	mm.seriesSet = nil
}

func (f *LogFile) execDeleteTagKeyEntry(e *LogEntry) {
	mm := f.createMeasurementIfNotExists(e.Name)
	ts := mm.createTagSetIfNotExists(e.Key)

	ts.deleted = true

	mm.tagSet[string(e.Key)] = ts
}

func (f *LogFile) execDeleteTagValueEntry(e *LogEntry) {
	mm := f.createMeasurementIfNotExists(e.Name)
	ts := mm.createTagSetIfNotExists(e.Key)
	tv := ts.createTagValueIfNotExists(e.Value)

	tv.deleted = true

	ts.tagValues[string(e.Value)] = tv
	mm.tagSet[string(e.Key)] = ts
}

func (f *LogFile) execSeriesEntry(e *LogEntry) {
	var seriesKey []byte
	if e.cached {
		sz := tsdb.SeriesKeySize(e.name, e.tags)
		if len(f.keyBuf) < sz {
			f.keyBuf = make([]byte, 0, sz)
		}
		seriesKey = tsdb.AppendSeriesKey(f.keyBuf[:0], e.name, e.tags)
	} else {
		seriesKey = f.sfile.SeriesKey(e.SeriesID)
	}

	// Series keys can be removed if the series has been deleted from
	// the entire database and the server is restarted. This would cause
	// the log to replay its insert but the key cannot be found.
	//
	// https://github.com/influxdata/influxdb/issues/9444
	if seriesKey == nil {
		return
	}

	// Check if deleted.
	deleted := e.Flag == LogEntrySeriesTombstoneFlag

	// Read key size.
	_, remainder := tsdb.ReadSeriesKeyLen(seriesKey)

	// Read measurement name.
	name, remainder := tsdb.ReadSeriesKeyMeasurement(remainder)
	mm := f.createMeasurementIfNotExists(name)
	mm.deleted = false
	if !deleted {
		mm.addSeriesID(e.SeriesID)
	} else {
		mm.removeSeriesID(e.SeriesID)
	}

	// Read tag count.
	tagN, remainder := tsdb.ReadSeriesKeyTagN(remainder)

	// Save tags.
	var k, v []byte
	for i := 0; i < tagN; i++ {
		k, v, remainder = tsdb.ReadSeriesKeyTag(remainder)
		ts := mm.createTagSetIfNotExists(k)
		tv := ts.createTagValueIfNotExists(v)

		// Add/remove a reference to the series on the tag value.
		if !deleted {
			tv.addSeriesID(e.SeriesID)
		} else {
			tv.removeSeriesID(e.SeriesID)
		}

		ts.tagValues[string(v)] = tv
		mm.tagSet[string(k)] = ts
	}

	// Add/remove from appropriate series id sets & stats.
	if !deleted {
		f.seriesIDSet.Add(e.SeriesID)
		f.tombstoneSeriesIDSet.Remove(e.SeriesID)
		f.stats.Inc(name)
	} else {
		f.seriesIDSet.Remove(e.SeriesID)
		f.tombstoneSeriesIDSet.Add(e.SeriesID)
		f.stats.Dec(name)
	}
}

// SeriesIDIterator returns an iterator over all series in the log file.
func (f *LogFile) SeriesIDIterator() tsdb.SeriesIDIterator {
	f.mu.RLock()
	defer f.mu.RUnlock()

	ss := tsdb.NewSeriesIDSet()
	allSeriesSets := make([]*tsdb.SeriesIDSet, 0, len(f.mms))

	for _, mm := range f.mms {
		if mm.seriesSet != nil {
			allSeriesSets = append(allSeriesSets, mm.seriesSet)
			continue
		}

		// measurement is not using seriesSet to store series IDs.
		mm.forEach(func(seriesID tsdb.SeriesID) {
			ss.AddNoLock(seriesID)
		})
	}

	// Fast merge all seriesSets.
	if len(allSeriesSets) > 0 {
		ss.Merge(allSeriesSets...)
	}

	return tsdb.NewSeriesIDSetIterator(ss)
}

// createMeasurementIfNotExists returns a measurement by name.
func (f *LogFile) createMeasurementIfNotExists(name []byte) *logMeasurement {
	mm := f.mms[string(name)]
	if mm == nil {
		mm = &logMeasurement{
			name:   name,
			tagSet: make(map[string]logTagKey),
			series: make(map[tsdb.SeriesID]struct{}),
		}
		f.mms[string(name)] = mm
	}
	return mm
}

// MeasurementIterator returns an iterator over all the measurements in the file.
func (f *LogFile) MeasurementIterator() MeasurementIterator {
	f.mu.RLock()
	defer f.mu.RUnlock()

	var itr logMeasurementIterator
	for _, mm := range f.mms {
		itr.mms = append(itr.mms, *mm)
	}
	sort.Sort(logMeasurementSlice(itr.mms))
	return &itr
}

// MeasurementSeriesIDIterator returns an iterator over all series for a measurement.
func (f *LogFile) MeasurementSeriesIDIterator(name []byte) tsdb.SeriesIDIterator {
	f.mu.RLock()
	defer f.mu.RUnlock()

	mm := f.mms[string(name)]
	if mm == nil || mm.cardinality() == 0 {
		return nil
	}
	return tsdb.NewSeriesIDSetIterator(mm.seriesIDSet())
}

// CompactTo compacts the log file and writes it to w.
func (f *LogFile) CompactTo(w io.Writer, m, k uint64, cancel <-chan struct{}) (n int64, err error) {
	f.mu.RLock()
	defer f.mu.RUnlock()

	// Check for cancellation.
	select {
	case <-cancel:
		return n, ErrCompactionInterrupted
	default:
	}

	// Wrap in bufferred writer with a buffer equivalent to the LogFile size.
	bw := bufio.NewWriterSize(w, indexFileBufferSize) // 128K

	// Setup compaction offset tracking data.
	var t IndexFileTrailer
	info := newLogFileCompactInfo()
	info.cancel = cancel

	// Write magic number.
	if err := writeTo(bw, []byte(FileSignature), &n); err != nil {
		return n, err
	}

	// Retreve measurement names in order.
	names := f.measurementNames()

	// Flush buffer & mmap series block.
	if err := bw.Flush(); err != nil {
		return n, err
	}

	// Write tagset blocks in measurement order.
	if err := f.writeTagsetsTo(bw, names, info, &n); err != nil {
		return n, err
	}

	// Write measurement block.
	t.MeasurementBlock.Offset = n
	if err := f.writeMeasurementBlockTo(bw, names, info, &n); err != nil {
		return n, err
	}
	t.MeasurementBlock.Size = n - t.MeasurementBlock.Offset

	// Write series set.
	t.SeriesIDSet.Offset = n
	nn, err := f.seriesIDSet.WriteTo(bw)
	if n += nn; err != nil {
		return n, err
	}
	t.SeriesIDSet.Size = n - t.SeriesIDSet.Offset

	// Write tombstone series set.
	t.TombstoneSeriesIDSet.Offset = n
	nn, err = f.tombstoneSeriesIDSet.WriteTo(bw)
	if n += nn; err != nil {
		return n, err
	}
	t.TombstoneSeriesIDSet.Size = n - t.TombstoneSeriesIDSet.Offset

	// Write trailer.
	nn, err = t.WriteTo(bw)
	n += nn
	if err != nil {
		return n, err
	}

	// Flush buffer.
	if err := bw.Flush(); err != nil {
		return n, err
	}

	return n, nil
}

func (f *LogFile) writeTagsetsTo(w io.Writer, names []string, info *logFileCompactInfo, n *int64) error {
	for _, name := range names {
		if err := f.writeTagsetTo(w, name, info, n); err != nil {
			return err
		}
	}
	return nil
}

// writeTagsetTo writes a single tagset to w and saves the tagset offset.
func (f *LogFile) writeTagsetTo(w io.Writer, name string, info *logFileCompactInfo, n *int64) error {
	mm := f.mms[name]

	// Check for cancellation.
	select {
	case <-info.cancel:
		return ErrCompactionInterrupted
	default:
	}

	enc := NewTagBlockEncoder(w)
	var valueN int
	for _, k := range mm.keys() {
		tag := mm.tagSet[k]

		// Encode tag. Skip values if tag is deleted.
		if err := enc.EncodeKey(tag.name, tag.deleted); err != nil {
			return err
		} else if tag.deleted {
			continue
		}

		// Sort tag values.
		values := make([]string, 0, len(tag.tagValues))
		for v := range tag.tagValues {
			values = append(values, v)
		}
		sort.Strings(values)

		// Add each value.
		for _, v := range values {
			value := tag.tagValues[v]
			if err := enc.EncodeValue(value.name, value.deleted, value.seriesIDSet()); err != nil {
				return err
			}

			// Check for cancellation periodically.
			if valueN++; valueN%1000 == 0 {
				select {
				case <-info.cancel:
					return ErrCompactionInterrupted
				default:
				}
			}
		}
	}

	// Save tagset offset to measurement.
	offset := *n

	// Flush tag block.
	err := enc.Close()
	*n += enc.N()
	if err != nil {
		return err
	}

	// Save tagset offset to measurement.
	size := *n - offset

	info.mms[name] = &logFileMeasurementCompactInfo{offset: offset, size: size}

	return nil
}

func (f *LogFile) writeMeasurementBlockTo(w io.Writer, names []string, info *logFileCompactInfo, n *int64) error {
	mw := NewMeasurementBlockWriter()

	// Check for cancellation.
	select {
	case <-info.cancel:
		return ErrCompactionInterrupted
	default:
	}

	// Add measurement data.
	for _, name := range names {
		mm := f.mms[name]
		mmInfo := info.mms[name]
		assert(mmInfo != nil, "measurement info not found")
		mw.Add(mm.name, mm.deleted, mmInfo.offset, mmInfo.size, mm.seriesIDs())
	}

	// Flush data to writer.
	nn, err := mw.WriteTo(w)
	*n += nn
	return err
}

// logFileCompactInfo is a context object to track compaction position info.
type logFileCompactInfo struct {
	cancel <-chan struct{}
	mms    map[string]*logFileMeasurementCompactInfo
}

// newLogFileCompactInfo returns a new instance of logFileCompactInfo.
func newLogFileCompactInfo() *logFileCompactInfo {
	return &logFileCompactInfo{
		mms: make(map[string]*logFileMeasurementCompactInfo),
	}
}

type logFileMeasurementCompactInfo struct {
	offset int64
	size   int64
}

// MeasurementCardinalityStats returns cardinality stats for this log file.
func (f *LogFile) MeasurementCardinalityStats() MeasurementCardinalityStats {
	f.mu.RLock()
	defer f.mu.RUnlock()
	return f.stats.Clone()
}

// LogEntry represents a single log entry in the write-ahead log.
type LogEntry struct {
	Flag     byte          // flag
	SeriesID tsdb.SeriesID // series id
	Name     []byte        // measurement name
	Key      []byte        // tag key
	Value    []byte        // tag value
	Checksum uint32        // checksum of flag/name/tags.
	Size     int           // total size of record, in bytes.

	cached   bool        // Hint to LogFile that series data is already parsed
	name     []byte      // series naem, this is a cached copy of the parsed measurement name
	tags     models.Tags // series tags, this is a cached copied of the parsed tags
	batchidx int         // position of entry in batch.
}

// UnmarshalBinary unmarshals data into e.
func (e *LogEntry) UnmarshalBinary(data []byte) error {
	var sz uint64
	var n int
	var seriesID uint64
	var err error

	orig := data
	start := len(data)

	// Parse flag data.
	if len(data) < 1 {
		return io.ErrShortBuffer
	}
	e.Flag, data = data[0], data[1:]

	// Parse series id.
	if seriesID, n, err = uvarint(data); err != nil {
		return err
	}
	e.SeriesID, data = tsdb.NewSeriesID(seriesID), data[n:]

	// Parse name length.
	if sz, n, err = uvarint(data); err != nil {
		return err
	}

	// Read name data.
	if len(data) < n+int(sz) {
		return io.ErrShortBuffer
	}
	e.Name, data = data[n:n+int(sz)], data[n+int(sz):]

	// Parse key length.
	if sz, n, err = uvarint(data); err != nil {
		return err
	}

	// Read key data.
	if len(data) < n+int(sz) {
		return io.ErrShortBuffer
	}
	e.Key, data = data[n:n+int(sz)], data[n+int(sz):]

	// Parse value length.
	if sz, n, err = uvarint(data); err != nil {
		return err
	}

	// Read value data.
	if len(data) < n+int(sz) {
		return io.ErrShortBuffer
	}
	e.Value, data = data[n:n+int(sz)], data[n+int(sz):]

	// Compute checksum.
	chk := crc32.ChecksumIEEE(orig[:start-len(data)])

	// Parse checksum.
	if len(data) < 4 {
		return io.ErrShortBuffer
	}
	e.Checksum, data = binary.BigEndian.Uint32(data[:4]), data[4:]

	// Verify checksum.
	if chk != e.Checksum {
		return ErrLogEntryChecksumMismatch
	}

	// Save length of elem.
	e.Size = start - len(data)

	return nil
}

// appendLogEntry appends to dst and returns the new buffer.
// This updates the checksum on the entry.
func appendLogEntry(dst []byte, e *LogEntry) []byte {
	var buf [binary.MaxVarintLen64]byte
	start := len(dst)

	// Append flag.
	dst = append(dst, e.Flag)

	// Append series id.
	n := binary.PutUvarint(buf[:], e.SeriesID.RawID())
	dst = append(dst, buf[:n]...)

	// Append name.
	n = binary.PutUvarint(buf[:], uint64(len(e.Name)))
	dst = append(dst, buf[:n]...)
	dst = append(dst, e.Name...)

	// Append key.
	n = binary.PutUvarint(buf[:], uint64(len(e.Key)))
	dst = append(dst, buf[:n]...)
	dst = append(dst, e.Key...)

	// Append value.
	n = binary.PutUvarint(buf[:], uint64(len(e.Value)))
	dst = append(dst, buf[:n]...)
	dst = append(dst, e.Value...)

	// Calculate checksum.
	e.Checksum = crc32.ChecksumIEEE(dst[start:])

	// Append checksum.
	binary.BigEndian.PutUint32(buf[:4], e.Checksum)
	dst = append(dst, buf[:4]...)

	return dst
}

// logMeasurements represents a map of measurement names to measurements.
type logMeasurements map[string]*logMeasurement

// bytes estimates the memory footprint of this logMeasurements, in bytes.
func (mms *logMeasurements) bytes() int {
	var b int
	for k, v := range *mms {
		b += len(k)
		b += v.bytes()
	}
	b += int(unsafe.Sizeof(*mms))
	return b
}

type logMeasurement struct {
	name      []byte
	tagSet    map[string]logTagKey
	deleted   bool
	series    map[tsdb.SeriesID]struct{}
	seriesSet *tsdb.SeriesIDSet
}

// bytes estimates the memory footprint of this logMeasurement, in bytes.
func (m *logMeasurement) bytes() int {
	var b int
	b += len(m.name)
	for k, v := range m.tagSet {
		b += len(k)
		b += v.bytes()
	}
	b += (int(m.cardinality()) * 8)
	b += int(unsafe.Sizeof(*m))
	return b
}

func (m *logMeasurement) addSeriesID(x tsdb.SeriesID) {
	if m.seriesSet != nil {
		m.seriesSet.AddNoLock(x)
		return
	}

	m.series[x] = struct{}{}

	// If the map is getting too big it can be converted into a roaring seriesSet.
	if len(m.series) > 25 {
		m.seriesSet = tsdb.NewSeriesIDSet()
		for id := range m.series {
			m.seriesSet.AddNoLock(id)
		}
		m.series = nil
	}
}

func (m *logMeasurement) removeSeriesID(x tsdb.SeriesID) {
	if m.seriesSet != nil {
		m.seriesSet.RemoveNoLock(x)
		return
	}
	delete(m.series, x)
}

func (m *logMeasurement) cardinality() int64 {
	if m.seriesSet != nil {
		return int64(m.seriesSet.Cardinality())
	}
	return int64(len(m.series))
}

// forEach applies fn to every series ID in the logMeasurement.
func (m *logMeasurement) forEach(fn func(tsdb.SeriesID)) {
	if m.seriesSet != nil {
		m.seriesSet.ForEachNoLock(fn)
		return
	}

	for seriesID := range m.series {
		fn(seriesID)
	}
}

// seriesIDs returns a sorted set of seriesIDs.
func (m *logMeasurement) seriesIDs() []tsdb.SeriesID {
	a := make([]tsdb.SeriesID, 0, m.cardinality())
	if m.seriesSet != nil {
		m.seriesSet.ForEachNoLock(func(id tsdb.SeriesID) { a = append(a, id) })
		return a // IDs are already sorted.
	}

	for seriesID := range m.series {
		a = append(a, seriesID)
	}
	sort.Slice(a, func(i, j int) bool { return a[i].Less(a[j]) })
	return a
}

// seriesIDSet returns a copy of the logMeasurement's seriesSet, or creates a new
// one
func (m *logMeasurement) seriesIDSet() *tsdb.SeriesIDSet {
	if m.seriesSet != nil {
		return m.seriesSet.CloneNoLock()
	}

	ss := tsdb.NewSeriesIDSet()
	for seriesID := range m.series {
		ss.AddNoLock(seriesID)
	}
	return ss
}

func (m *logMeasurement) Name() []byte  { return m.name }
func (m *logMeasurement) Deleted() bool { return m.deleted }

func (m *logMeasurement) createTagSetIfNotExists(key []byte) logTagKey {
	ts, ok := m.tagSet[string(key)]
	if !ok {
		ts = logTagKey{name: key, tagValues: make(map[string]logTagValue)}
	}
	return ts
}

// keys returns a sorted list of tag keys.
func (m *logMeasurement) keys() []string {
	a := make([]string, 0, len(m.tagSet))
	for k := range m.tagSet {
		a = append(a, k)
	}
	sort.Strings(a)
	return a
}

// logMeasurementSlice is a sortable list of log measurements.
type logMeasurementSlice []logMeasurement

func (a logMeasurementSlice) Len() int           { return len(a) }
func (a logMeasurementSlice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a logMeasurementSlice) Less(i, j int) bool { return bytes.Compare(a[i].name, a[j].name) == -1 }

// logMeasurementIterator represents an iterator over a slice of measurements.
type logMeasurementIterator struct {
	mms []logMeasurement
}

// Next returns the next element in the iterator.
func (itr *logMeasurementIterator) Next() (e MeasurementElem) {
	if len(itr.mms) == 0 {
		return nil
	}
	e, itr.mms = &itr.mms[0], itr.mms[1:]
	return e
}

type logTagKey struct {
	name      []byte
	deleted   bool
	tagValues map[string]logTagValue
}

// bytes estimates the memory footprint of this logTagKey, in bytes.
func (tk *logTagKey) bytes() int {
	var b int
	b += len(tk.name)
	for k, v := range tk.tagValues {
		b += len(k)
		b += v.bytes()
	}
	b += int(unsafe.Sizeof(*tk))
	return b
}

func (tk *logTagKey) Key() []byte   { return tk.name }
func (tk *logTagKey) Deleted() bool { return tk.deleted }

func (tk *logTagKey) TagValueIterator() TagValueIterator {
	a := make([]logTagValue, 0, len(tk.tagValues))
	for _, v := range tk.tagValues {
		a = append(a, v)
	}
	return newLogTagValueIterator(a)
}

func (tk *logTagKey) createTagValueIfNotExists(value []byte) logTagValue {
	tv, ok := tk.tagValues[string(value)]
	if !ok {
		tv = logTagValue{name: value, series: make(map[tsdb.SeriesID]struct{})}
	}
	return tv
}

// logTagKey is a sortable list of log tag keys.
type logTagKeySlice []logTagKey

func (a logTagKeySlice) Len() int           { return len(a) }
func (a logTagKeySlice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a logTagKeySlice) Less(i, j int) bool { return bytes.Compare(a[i].name, a[j].name) == -1 }

type logTagValue struct {
	name      []byte
	deleted   bool
	series    map[tsdb.SeriesID]struct{}
	seriesSet *tsdb.SeriesIDSet
}

// bytes estimates the memory footprint of this logTagValue, in bytes.
func (tv *logTagValue) bytes() int {
	var b int
	b += len(tv.name)
	b += int(unsafe.Sizeof(*tv))
	b += (int(tv.cardinality()) * 8)
	return b
}

func (tv *logTagValue) addSeriesID(x tsdb.SeriesID) {
	if tv.seriesSet != nil {
		tv.seriesSet.AddNoLock(x)
		return
	}

	tv.series[x] = struct{}{}

	// If the map is getting too big it can be converted into a roaring seriesSet.
	if len(tv.series) > 25 {
		tv.seriesSet = tsdb.NewSeriesIDSet()
		for id := range tv.series {
			tv.seriesSet.AddNoLock(id)
		}
		tv.series = nil
	}
}

func (tv *logTagValue) removeSeriesID(x tsdb.SeriesID) {
	if tv.seriesSet != nil {
		tv.seriesSet.RemoveNoLock(x)
		return
	}
	delete(tv.series, x)
}

func (tv *logTagValue) cardinality() int64 {
	if tv.seriesSet != nil {
		return int64(tv.seriesSet.Cardinality())
	}
	return int64(len(tv.series))
}

// seriesIDSet returns a copy of the logMeasurement's seriesSet, or creates a new
// one
func (tv *logTagValue) seriesIDSet() *tsdb.SeriesIDSet {
	if tv.seriesSet != nil {
		return tv.seriesSet.CloneNoLock()
	}

	ss := tsdb.NewSeriesIDSet()
	for seriesID := range tv.series {
		ss.AddNoLock(seriesID)
	}
	return ss
}

func (tv *logTagValue) Value() []byte { return tv.name }
func (tv *logTagValue) Deleted() bool { return tv.deleted }

// logTagValue is a sortable list of log tag values.
type logTagValueSlice []logTagValue

func (a logTagValueSlice) Len() int           { return len(a) }
func (a logTagValueSlice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a logTagValueSlice) Less(i, j int) bool { return bytes.Compare(a[i].name, a[j].name) == -1 }

// logTagKeyIterator represents an iterator over a slice of tag keys.
type logTagKeyIterator struct {
	a []logTagKey
}

// newLogTagKeyIterator returns a new instance of logTagKeyIterator.
func newLogTagKeyIterator(a []logTagKey) *logTagKeyIterator {
	sort.Sort(logTagKeySlice(a))
	return &logTagKeyIterator{a: a}
}

// Next returns the next element in the iterator.
func (itr *logTagKeyIterator) Next() (e TagKeyElem) {
	if len(itr.a) == 0 {
		return nil
	}
	e, itr.a = &itr.a[0], itr.a[1:]
	return e
}

// logTagValueIterator represents an iterator over a slice of tag values.
type logTagValueIterator struct {
	a []logTagValue
}

// newLogTagValueIterator returns a new instance of logTagValueIterator.
func newLogTagValueIterator(a []logTagValue) *logTagValueIterator {
	sort.Sort(logTagValueSlice(a))
	return &logTagValueIterator{a: a}
}

// Next returns the next element in the iterator.
func (itr *logTagValueIterator) Next() (e TagValueElem) {
	if len(itr.a) == 0 {
		return nil
	}
	e, itr.a = &itr.a[0], itr.a[1:]
	return e
}

// FormatLogFileName generates a log filename for the given index.
func FormatLogFileName(id int) string {
	return fmt.Sprintf("L0-%08d%s", id, LogFileExt)
}


The present invention pertains to a process for continuously preparing powder lubricants to use in dry wiredrawing and/or in cold metal rolling, the apparatus to put the process into practice, and the powder lubricants thus obtained.
By wiredrawing it is generally meant a process in which a material being worked is cold deformed without removal of chips by pulling it through special matrices called dies so as to reduce its section up to the desired diameter or profile the section thereof according to the desired shapes.
Cold rolling is instead a process by which a material being worked is cold deformed without removal of chips by means of special rotating rolls. Obviously the friction of the wire through the die or rolls is in both cases very strong.
In order to eliminate or reduce said friction it is necessary to resort to lubrication, which consists in interposing substances which may be greasy, solid or liquid and are exactly called lubricants, between the sliding surfaces.
Currently, powder lubricants are increasingly used in the field of dry wiredrawing and/or cold rolling. They generally consist of metal salts of fatty acids added with inert mineral charges and additives.
The first wide-spread procedure to prepare powder lubricants consisted in mixing the components in a mixer until a homogeneous mass was achieved, then the product was distributed into appropriate tray-like containers and finally said containers were disposed in a furnace in which baking took place. The finished product thus obtained was then ground and brought to the desired granulometry.
It is clear that such a procedure needed very long working times, gave a reduced yield and involved an important waste of man-power and energy while offering insufficient security to the persons attending to the apparatus.
A further method of production substantially quicker and less hard than the preceding one, provides the use of a bladed mixer, heated to a temperature of 100.degree. to 300.degree. C., in which components are simultaneously mixed and baked during a period of time ranging between 60 and 90 minutes.
The mixture is afterwards taken out and then ground.
Although the last mentioned method is better than the preceding one, it suffers the disadvantage that at the end of the mixing and baking operations the production cycle must be interrupted to allow the discharging of the baked product and the charging of raw materials necessary for the next working cycle.


The news channel’s helicopter captured the “complete gridlock” on the 405 motorway, one of the busiest and most congested routes in the United States.

ABC7 shared the footage on social media, joking that the motorists appeared to be attempting the Mannequin Challenge.

The footage racked up millions of views within a few hours of being uploaded, with Facebook user Gps Erick commenting: “Are you sure that's traffic? Maybe they decorated the 405 with Christmas lights.”


MEDREG and the Energy Community Regulatory Board (ECRB), representing Energy Regulators of the Mediterranean and the Eastern and Black Sea regions, joined forces to review the procedures available to energy consumers to handle complaints and settle disputes.The two organisations also proposed best practices.

This report maps out the current status and nature of complaint handling, dispute settlement and consumer awareness in Eastern Europe and Mediterranean countries. It is accompanied by recommendations applicable to disputes between consumers and their providers.

Based on a survey answered by 19 members from MEDREG and ECRB, the report reveals that regardless of the level of customers’ protection, consumers’ protection is gaining a growing interest.

Here are the main findings gleaned by the survey:

? All respondent countries have energy consumer protection policies in place. In most cases, National Regulatory Authorities (NRAs) are responsible to review complaints and resolve disputes with clear procedures in place while in some minor cases other entities, such as judicial institutions, handle them.

? In almost all the respondent countries the energy service provider informs the customers about relevant information concerning price connection and disconnection rules and fees terms of bill payments dispute rules.

? Consumers are informed about their right to complain via contracts, websites and leaflets.

? In most countries, consumers raise a complaint through the supplier’s own mechanisms in the first instance, before turning to the regulator. Various means are available to customers to contact the regulator and to address their complaints, the most innovative being the use of messaging applications and social media.

? All regulators have access to complaint-related data, which is ensured by law.

? Billing and metering issues are the most common topics on which complaints are received.

? All NRAs must address complaints within specific periods, ensuring that customers receive redress or treatment of their complaint within an adequate timeframe.

? In nearly all cases, including in recourses to voluntary Alternative Dispute Resolution (ADR) procedures, the final settlement determined by the regulator or reached by the parties is binding, and in the case of a regulatory decision, subject to fines and enforcement in the case of non-compliance by the service provider.

? As a next step, ECRB and MEDREG will seek to publicly discuss the findings of this report to bring the understanding of customers’ rights protection to the attention of high level stakeholders and ensure more accountable responses from the authorities.

Best Regards,MEDREGMediterranean Energy Regulators

MEDREG is co-funded by the European Union.
The contents of this document are the sole responsibility of MEDREG
and can under no circumstances be regarded
as reflecting the position of the European Union.


The grass is spotty, the dirt patches shine through. The field isn’t what you’d expect for an Ultimate Frisbee league, as it is centered in the outfield of a prison softball field. Yet, a little over a dozen men, convicts, stand at the ready. Some wearing gloves, some shirtless with all manner of tattoos, and the field is marked with orange pylons commandeered from the prison flag football league. This is Frisbee, prison Frisbee.

When people think of federal prison they think of hardened convicts. They think of razor wire and gun towers. They think of stabbings, stompings, and race conflicts. They think of prison guards, their mace and their batons. Such of these thoughts are applicable. Just yesterday someone was stomped in the prison chow hall for sitting at the wrong table. Prison is prison, and what happens in prison simply happens. But perhaps when people think about prison they should think too of sports leagues, camaraderie, and healthy competition, albeit competition with teeth. After all, this is prison sports we’re talking about, not an intramural league at a liberal arts college. Most of us are serving sentences in excess of five or even 10 years; some may never go home.

As the Frisbee players of FCI Petersburg – a medium security federal prison in Petersburg, Virginia – group up, they start to throw around a few Frisbees. Long games of catch ensue in the pre-game dawn light. Games here are often pick-up and last from 6 PM to 8 PM. These times coincide with the “activities moves,” when the reinforced internal prison gates – gates topped with razor wire and security cameras, of course – are opened and prisoners are allowed to move to different locations within the prison. While there are weeks when only one or two games are played, there have literally been complete months when everyone comes out and plays for every single night. Again, this isn’t regular Frisbee, it is prison Frisbee, and the stakes aren’t about wins on a scoreboard – of which we have none – but more about identity and a sense of being. Hey, we’re in prison and we need something to grasp in an effort to find meaning in life, even if for only a few hours a week, and even if only a small part of our identity.


The pharmacokinetics of 2,2',5,5'-tetrachlorobiphenyl and 3,3',4,4'-tetrachlorobiphenyl and its relationship to toxicity.
The pharmacokinetics of two toxicologically diverse tetrachlorobiphenyls (TCBs) were measured in mice. After dosing to apparent steady-state conditions, 2,2',5,5'-TCB was found to have a tissue elimination half-life of between 1.64 and 2.90 days. The half-life of 3,3',4,4'-TCB was similar, ranging from 1.07 to 2.60 days. Systemic clearance and volume of distribution estimates were also similar for the two TCB isomers. The 3,3',4,4'-isomer had a substantially greater partitioning from serum into adipose, liver, and thymic tissues. With dosing regimens developed using these measured pharmacokinetic parameters, experiments were undertaken to compare toxic potency of these two TCBs when similar tissue concentrations of the two isomers were achieved in target and storage tissues. These studies demonstrated that thymic atrophy occurs at lower 3,3',4,4'-TCB doses and tissue concentrations than those required to produce hepatotoxicity. These two organ toxicities were produced only by 3,3',4,4'-TCB despite the fact that equivalent or higher tissue concentrations of 2,2',5,5'-TCB were achieved in vivo in all tissues. We conclude that the in vivo difference in the toxic potency of these two TCB isomers does not result from the significant differences in their tissue disposition, elimination, and ultimate bioaccumulation.


"[ Men Grunting ]" "There!" "All right!" "Unload those barrels over that way!" "Just set it on my shoulders." "That's right." "Good." "All of it." "That'll do it." "By the gods!" "Hmm." "[ Chuckling ]" "Nice chest we got here, boys." "[ Men Laugh ]" "[ Man ] What about the legs, Captain?" "[ Captain ] Hey!" "Step aside, ya mongrels." "The island's deserted, Captain." "Good." "When King Zolas realizes we grabbed... his, uh, family jewels, [ All Chuckling ] he'll have every bounty hunter from here to Hellespont lookin' for us." " Unload the rest of it." "We'll bury it there." "Aye, aye, Captain!" "Let's move it!" "You know I wouldn't question you in front of the men, Captain, but the Charybdean Sea is a known graveyard for ships, and it's our only way outta here." "That's why Zolas would never look for us here." "Don't worry." "If we die, we die rich." "[ Chuckling ]" "[ Shovel Banging ] Captain!" "You better take a look at this." "[ Man ] What in Tartarus?" "[ Man ] Over here." "What is it, Captain?" "No idea." "Dig it up." "[ Man ] Go on." "You heard the captain." "[ Hercules ] Watch the rope!" "It's about to give!" " [ Grunts ]" " Bromius!" "What happened?" "Give him a hand!" "Pull him out of there!" "You all right?" "Fine." "We've stopped the flooding, Captain, but she won't hold for long." "The storm's movin' this way, Cercetes." "We're gonna have to make some repairs." "You think we can do it before the storm hits?" "Let's not push our luck." "We've already lost too many men." "You're right." "We'll put in and wait for clear skies." "Sorry, Hercules, but I'm gonna have to get ya back to Corinth a little later than I hoped to." "Don't worry about it." "You're all right." "I'm just glad we're on dry land." "I just hope our ship survives the storm." "Ooh, spooky." "[ Low Growling ]" "We're not the only ones here." "Yeah." "Somebody's been busy." "Well, well, well." "By the gods!" "I, uh" " I think I found something!" "There's more." "Over here." "Oh, look at all this stuff!" "We're rich!" "We're rich!" "[ Boisterous Laughter ]" "They were burying this stuff." "You thinking what I'm thinking?" "Pirates." "So where did they go?" "[ Chuckles ] Everywhere." "And they left in a hurry." "[ Man Narrating ] This is the story of a time long ago, a time of myth and legend, when the ancient gods were petty and cruel, and they plagued mankind with suffering." "Only one man dared to challenge their power" "Hercules." "Hercules possessed a strength the world had never seen, a strength surpassed only by the power of his heart." "He journeyed the earth, battling the minions of his wicked stepmother, Hera, the all-powerful queen of the gods." "But wherever there was evil, wherever an innocent would suffer, there would be..." "Hercules." " [ Screeching ] - [ Roaring ]" "Hail!" "[ Both Laughing ]" "Hey!" "Don't celebrate yet, fellas." "This treasure isn't yours." "What?" "We found it!" "Yeah!" "Finders keepers!" "These chests have Corillian seals." "So?" "They belong to King Zolas." "Well, there's no seal on my bag!" "Yeah, mine neither!" "Shut up!" "Hercules is right." "Hey, listen, tree trunk." "You're not the captain!" "No, he's not!" "But I am." "We return the treasure, and that's that." "Hercules, there's a lot of equipment back there." "We could use it to repair the boat." "Yeah." "But first, let's find out who left it here, or at least why." "We'll split up and meet back here later." "I'll stay here and set up camp." "Paxxon, Bromius, come with me." "Why does Monicles get to hang out and relax?" "Paxxon." "What?" "Now!" "Oh, yeah, lookin' forward to this." "Well, Iolaus." "This is another fine mess you've gotten us into." "Funny." "Very funny." "Close-knit crew, huh?" "Yeah, like a family." "Remind me never to hitch a ride with strangers again." "Actually, that's pretty good advice." "Oh, thanks, Hercules." "What in Tartarus is that?" "[ Hercules ] It's, uh, some sort of cocoon." "What for?" "Giant butterfly?" "[ Chuckles ]" "Somehow, I don't think it's gonna turn out to be that friendly." "[ Screaming ] How come you're always right?" "It's a half-god thing." "Yeah." "Disgusting!" "[ Hercules ] Looks like he died defending himself." " From what?" " [ Groans ] It stinks." "[ Moans ]" "[ Retching ]" " What happened to his face?" "Looks like it just melted off." "We found something back there." "There's a cocoon." "What kind of cocoon?" "I'm not sure." "I've never seen anything like it." "Hercules, uh, you know, what came out of that cocoon could have" " It's possible." " Ah, you're kidding, right?" "I guess we know why those pirates left in such a hurry." "Well, we're not gonna be going anywhere with this storm coming on." "Oh, great." "We'll just sit around and wait for our faces to melt off." "If we stay together, we'll be fine." "As soon as the storm passes, we'll get out of here." "[ Thunderclaps ]" "Let's bury him." "What's takin' 'em so long?" "My, my." "There once was a sailor named Monicles... who couldn't be rich '''cause of Hercules." "As soon as he left, [ Hissing ]" "I started my theft." "[ Rustling ]" "The rest will have to wait till later." "Hello!" "[ Screaming ]" "Something's cookin'." "Monicles?" "[ Thunderclap ]" "[ Sighs ] Look what we have here." " I guess his pockets weren't big enough." " That snake!" "So where is he, huh?" "Maybe he tried to take his chances without us." "I don't think so." "He may be greedy, but he's not stupid." "Could have fooled me." "So what are you saying, man?" "Huh?" "He's dead, isn't he?" "He's dead, isn't he?" " He's dead and his whole face is melted off!" " I'm so sick of your whining!" "But, man, he's dead!" "His face is all melted off!" "Grow a spine, you coward!" "Don't push me, you great big oaf!" "Come on" "Hey, hey, hey, hey, hey!" "Cut it out, both of you!" "This isn't helping us find Monicles." "Find him?" "Why bother to find him?" "He's dead!" "We can't be sure of that." "We gotta go and look for him." "I'm not goin' anywhere." "Suit yourself." "Yell if you run into any trouble." "Bye-bye, Paxxon." "Have fun!" "No, I'm not goin' anywhere." "No, anywhere." "I'm not goin' anywhere." "[ Thunderclap ]" "Hey, wait for me!" "Guys?" "Hello?" "Monicles!" "[ Rustling ] - [ All Gasp ]" "What was that?" "I do believe..." "we have company." "Okay." "Back up slowly." "No, wait!" "My leg!" " Woof." " You all right?" " It's just a flesh wound." " Well, take care of it." "[ Hercules ] Iolaus, let's go!" "Hello." "Ah!" "Nice to see ya again." "How ya doin'?" "[ Groans ]" "Who are you?" "Who are you?" "No, let me guess." "Sloping forehead, dragging knuckles." "I'm thinkin' orangutan." "Maybe gorilla." " [ Moaning ]" " Ah, that must be your little chimp." "I'm laughing inside." "We weren't tryin' to hurt you." "Yeah, right." "Could have fooled me." "This is Iolaus." "I'm Hercules." "Never thought the mighty Hercules would stoop to bounty hunting." "What's wrong?" "Hero business not paying so well these days?" "Not as well as piracy, I take it." "You stole the treasure, huh?" "Yeah, yeah." "Look, whatever King Zolas is paying you, I'll double it." "But we have to get out of here now." "King Zolas didn't send us." "We don't take bribes." "Yeah, especially from pirates." "So you're not after me?" "No." "Well, in that case, I'm Nebula," "Captain of theLeviathan." "And you boys have come to the wrong place at the wrong time." "[ Voices Screaming ]" "This ought to stop the bleeding." "I'm fine." "Let's go." "Take it easy." "Paxxon, give me a hand." "Paxxon?" "Paxxon?" "That coward." "Probably got spooked by his own shadow!" "Boo!" "[ Gasps ] What in Tartarus are you doing?" " You jackass." " Ooh, man, the look on your face." "Well, who's the coward now, huh?" "Paxxon!" "That's enough." "I'm tryin' to make a point here, Captain." "If the point is you're a fool, you've made it." "Now shut up!" "I'm gonna tear your head off." " I'm gonna rip off your arms and beat you with '''em!" " Nyah, nyah, nyah, nyah, nyah." "Well, first you'll have to catch me!" "Paxxon, that's enough." " [ Laughing ]" "I said that's enough!" "Whoa!" "What was that?" " [ Screeching ] - [ Screams ]" "[ Screaming ]" "[ Screaming ]" "[ Screaming Continues ]" "It took Bromius!" "Oh, man!" "It took Bromius!" "[ Iolaus ] "It" what?" " I" " I don't know!" "[ Strained Voice ] Hercules, help me!" "Hang on, Cercetes." "We'll get you out of here." " You ever seen anything like this before?" " I have." "Out of the way." "I know you don't want him to keep suffering." "Please, anything." "The pain." "You better know what you're doing." "I do." " Oh!" " [ Gasps ]" "Why?" "The same thing happened to my first mate!" "I did everything that I could, but he died slow and painful." "Get it?" "That must be the body we found." "I did your friend a favor." "Now get your hands off me." "With pleasure." "Keep talking." "I landed here with a crew of 20." "We found something in the ground and I told them to dig it up." "Whatever that thing is took them all in less than a day... because I was curious about what it was." " So what happened to your ship?" " The hurricane set it adrift." "It's at the bottom of the sea by now." "Sorry about your crew." "But where I come from, we don't give up on people." "Is that right?" "Well, I admire your idealism, Hercules." "I really do." "But in case you haven't noticed, the rules are a little different here." "And by the way, if I end up like him," "I hope one of youmen has the guts to do the same for me." "Hercules." "Look at this." "What do you think it is?" "It's blood." "[ Paxxon ] Blood?" " Cercetes must have wounded it." " And look what happened to him." "Did you see it?" "Well, it-it was too fast." "It moves in the shadows." "We never saw it coming." "Then we've got no choice." "We find it before it finds us." "[ Thunderclap ]" "This way." "In there." "[ Groaning ]" "Something I can help you with?" "Yeah, I was, uh-- I was just lookin' at your tattoos." "Look." "Don't touch." "Didn't they hurt?" "Only the first time." "What's that?" "Poseidon's trident." "Keeps the wind at my back." "I see you have an Eastern calendar." "Yeah, helps me keep track of the seasons." "You've been to the East." "Well, that's where we both learned to fight, I take it." "How long were you in prison?" "On your neck, that's a Spartan prison marking." "[ Chuckles ] Funny." "I don't remember seeing you there." "You could say I gave some people... directions." "Well, I bet you did." "Something you wanna say to me?" "Only that I don't trust you." "That's your problem, '''cause until we get off this rock, you don't have much of a choice." "When we do get off this rock, you and that treasure you took are going back to King Zolas." "If you can get us out of here alive, Hercules, I'll think about it." "You do that." "Hercules, this is it." "Looks like the trail ends here." "[ Rustling ]" "[ Screeching ]" "Look out!" "That is one big spider." "[ Hissing ]" " Ha!" " [ Screeching ]" "Hercules?" "Hercules, don't leave me here!" "Please!" "[ Laughing ]" "Hercules, hurry up!" "Paxxon." "Hercules!" "Paxxon, hang on!" "Don't move, Paxxon!" "I'll be right there." "[ Screeching ]" "[ Thunderclap ] Uh-uh." "Hercules, I'm outta here!" "No!" "Stay where you are!" "Come on!" "Come on!" "Paxxon!" "Paxxon!" "This way!" "Paxxon!" "Stop running!" "Paxxon!" "Whoa!" "[ Screeching ]" "[ Screaming ]" "Paxxon!" "Paxxon!" "Paxxon!" "[ Thunderclaps Continue ]" "I say we hop on that ship and take our chances." "You wanna sail through a hurricane in a leaky boat?" " You got a better idea?" " Forget the ship, Nebula." "We'd never make it." "At least we'd have a chance." "We don't even know what we're up against here." "I do." "Her name is Arachne." "She was a queen." "Very vain, very cruel, very beautiful." "But her daughter was even more beautiful than she was." "So Arachne threw her own child into the sea." "So the gods put a curse on her, right?" " Exactly." " They did a good job too." "When the gods curse people, why can't they turn 'em into a gerbil or a hamster?" "Yeah, something we could drop-kick." "[ Chuckles ] It's gonna take a lot more than that to stop her." "Well, as long as we're blundering around here in the dark, we're at a big disadvantage." "Arachne moves in the shadows because she's ashamed of her appearance." "Light is her enemy." "You thinking what I'm thinking?" "Let's light this place up." "[ Insects Buzzing ]" "Wearily, the rose petals fell... when the sun turned its back." "Who are you?" "[ Shuddering ]" "Do you think I'm... beautiful?" "Yes." "[ Sighs ]" "Please, let me go." "[ Shudders ]" "There's nothing more exciting... than the look on a man's face... when he knows he's about to die." "Please, I'll do anything." "Shh." "I want to give you a part of myself-- something you'll keep deep inside." "[ Muffled Groans ]" "You're sure all these tunnels lead through here?" "Yeah, I'm sure." "All right." "Keep those torches handy." "Don't worry." "Nothing gets in here we don't see it." "We'll be okay." "Yeah." "Well, don't start the barbecue without me." "Yeah." "Be safe." "You too." "Good luck." "You too." "[ Chuckling ] What?" "Hey, nothing." "Quite a firm handshake between you two." "Yeah, so?" "So, I think it's great." "Well, I'm glad you approve." "Yeah." "So, how long you two been together?" "We've been partners since we were kids." "Oh, "partners."" "Do you ever think anything you didn't say?" "Life's just too, um, short to mince words, Goldilocks." "You know, Nebula, if you're trying to get a rise out of me, it ain't gonna work." "If I were tryin' to get a rise out of you, [ Gasps ] you'd know it." "Ah." "Now I recognize you." "Hmm?" "You're the woman my mother warned me about." "Mmm." "[ Chuckling ]" "Ah." "Anything?" "Not a sign of her." "This doesn't make sense." "She has to come through here." "Something's not right." "Yeah, like maybe there's a passageway you don't know about." "Look, this wasn't my idea." "[ Screeching ]" "You hear it?" "Oh, yeah." "But where is it?" "She's here." "There's nothing here." "Look out!" "Iolaus, behind you!" "[ Screaming ] [ Screeching ]" "Hercules!" "[ Screams ] Hercules!" "Help!" "Hercules!" "Iolaus!" "Hercules!" "He's gone!" "Then I have to find him." "No, it's over." "Iolaus is dead." "You don't know that." "I know what it's like." "My crew was as close to me as family, but he's gone and he's not comin' back." "And we have to get out of here while we still can." "I told you before:" "Where I come from we don't give up on people." "I know he was your friend, but I won't let you get me killed." "Then go." "I'm not askin' for your help." "But I hope you can live with yourself." "[ Thunderclap ]" "[ Insects Buzzing ]" "[ Grunting ]" "Paxxon?" "[ Gasping ]" "By the gods!" "[ Gasps ]" "The gods won't help you now." "Your friend felt no pain." "Neither will you." "Thanks." "That's very comforting." "[ Shudders ]" "Do you think..." "I'm beautiful?" "Yeah." "I like bugs." "So brave, willing to face death." "You'll be a loss to your kind, but a welcome addition to my family." "[ Muffled Groans ]" "Arachne!" "Get a room." "[ Hisses ] Hope I'm not spoiling the mood." "Oh, you are." "I was just gettin' into it." "Who are you?" "He's Hercules." "I can't say I'm pleased to meet you." "Oh, but I am pleased to meet you, Hercules." "Son of Zeus, who cursed me with this form." "You'll pay for your father's crime." "What else is new?" "Hercules, look out!" "[ Screaming, Groans ]" "[ Sighs ] This is one big web site." "Where were we?" "[ Sighing ]" "Ow!" "[ Screams ]" "I'm curious." "How long does it usually take you to shave those legs?" "[ Hissing ]" "Yeehaw!" "Don't bother getting up." "We'll show ourselves out." "What happened to you?" "[ Nebula ] Eew!" "[ Moans ]" "Now, let me show you how to damage a face!" "[ Hercules ] Hey!" "[ Moaning ]" "I wouldn't try that if I were you." "[ Groans ]" "[ Screeching ]" "You won't kill your own men." "Nice try, but they're already dead." "True, but they didn't die in vain." "From each death comes new life." "Spreading hatred isn't much of a life." "I prefer to think of it as spreading beauty." "The world will know true beauty once again." "You're fooling yourself, Arachne." "Ah." "Is this where you usually hang out?" "Ha, ha." "Hey." "Trust me." "[ Screaming ] [ Grunts ]" "I prefer to be on top." " [ Screeching ]" " Look out!" "Where did that come from?" "You don't wanna know." "I will reclaim the throne." "My army, born from the bodies of these men, will see to that!" "Sorry." "I'm gonna pull rank." "[ Screeching ]" "[ Hissing ]" "[ Screams ]" "Much better." "[ Chuckles ]" "[ Grunting ]" "[ Laughing ] I'm quite enjoying this, Hercules." "I could go on and on for days." "Sorry, but you'll have to play with yourself." "No!" "[ Screaming ]" "Well done." "[ Muffled Screams ]" "[ Coughing ] I think it likes you." "You know, I think what we need is a really big shoe." " Hercules!" "[ Screeching ]" "Get this thing off of me!" "Iolaus!" " On three!" " Okay." "Three!" "[ Sighs ] [ Chuckles ]" "Eew." "Overall, I'd have to say this has been a very disgusting day." "Yeah." "Hey, nice throw." "Nice assist." "Ah, thanks, buddy." "I hate to interrupt this really lovely moment, but can we go now?" "Yeah, sure." "Why don't you lead the way." "Yeah." "Is it me, or are you gettin' real comfortable with my goods?" "This treasure's going back to King Zolas, just like I told you." "Oh." "Now why'd you have to go and say a thing like that, huh?" "We go back there, he'll hang me." "I said the treasure's going back, not you." "Oh." "Well, guess it's worth a ticket out of that cave." "Don't wanna see any more of that." "I'm glad you changed your mind..." "about a lot of things." "Well, someone had to save your butts." "Right?" "[ Chuckles ]" "Did I, uh, miss something back there?" "All right!" "Let's get this bucket shipshape, huh?" "Hercules, trim the mainsail!" "Iolaus, hop up there and secure that mast!" "I'll be waiting, monkey boy." "Uh-huh." "Nah, you missed nothing." "You know, Herc, we should be pirates." "Hmm." "The two of us, swashbuckling!" "Yeah, I'd be good at buckling swashes." "In fact, you can call me Goldenbeard from now on." "Ow!" "[ Moaning ]" "So what'd you see?" "Closed-Captioned By Captions, Inc., Los Angeles"


Q:

Where can I find a list of CAMLvariables and ServerVariables?

Having some trouble finding a list of these variables. Any help would be greatly appreciated.
More specifically, when I see this on the page:
<ParameterBinding Name="UserID" Location="CAMLVariable" DefaultValue="CurrentUserName"/>

I want to know what other CAMLVariable exist. This also of course includes ServerVariables as well.

A:

Here's the reference to Server Variables from my blog:
http://mdasblog.wordpress.com/2007/10/19/data-view-web-part-parameters-based-on-server-variables/

A:

Query schema: http://msdn.microsoft.com/en-us/library/ms467521.aspx


//
//  PaginationEntity.m
//  PHPHub
//
//  Created by Aufree on 9/22/15.
//  Copyright (c) 2015 ESTGroup. All rights reserved.
//

#import "PaginationEntity.h"

@implementation PaginationEntity

+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    return @{
             @"totalPages" : @"total_pages",
             @"currentPage" : @"current_page",
             @"perPage" : @"per_page"
             };
}

@end


Q:

Adjoining two primitive n-th roots

Let $\omega_n$ denote a primitive $n^{th}$ root of unity. If $m$ and $n$ are positive integers with $lcm(m,n)=k$, show that $\mathbb{Q}(\omega_n,\omega_m)=\mathbb{Q}(\omega_k)$.
To start, I am aware that $(\omega_n\omega_m)^k=1$, and so $o(\omega_n\omega_m)|k$, I am working towards showing that $o(\omega_n\omega_m)$ is in fact equal to $l$ (although I don't know this to be true at this point). This would show that $\mathbb{Q}(\omega_n,\omega_m)$ contains a primitive $k-th$ root of unity and thus all of $\mathbb{Q}(\omega_k)$. Any help would be appreciated, I think I am over thinking things (especially regarding the other direction of the inclusion).

A:

This may become obvious if you write everything additively instead of multiplicatively.
That is, you know the $k$-th roots of unity are a cyclic group under multiplication of order $k$, and so it is isomorphic to the integers modulo $k$ under addition. Use the isomorphism to translate the original problem into a question about integers modulo $k$.


import React from 'react';
import createHistory from 'history/createBrowserHistory';
import { Router } from 'react-router';
import { storiesOf } from '@storybook/react';

import Login from 'shared/components/login/login';

const history = createHistory();

storiesOf('shared/components/login', module)
  .add('Basic', () => (
    <Router history={history}>
      <Login />
    </Router>
  ));


Q:

Express session authentification and assigning variables

I am facing weird issue. I believe its very simple to experienced people.
Making local web server on Node.js+Express+NeDB
Client on login makes POST request to /login form and is redirected on successful login.
{"id":1,"created":1568146217901,"username":"sprice","name":"Steve Price","email":"email@gmail.com","password":"Password","level":"1","_id":"3JDE7p6tAl1vD11k"}
Login post
// POST services
app.post('/login', (req, res) => {
    const loginData = req.body;
    db.users.findOne({ username: loginData.uname }, function (err, doc) {
        req.session.userId = doc.id;
        if(doc.id === 1) console.log("True"); // < Output: True
        console.log(req.session.userId); // < Output: 1
    });
    req.session.userId = 1; // < Just for test
    res.redirect('/plan');
});

Before going into /plan page there is an auth check:
const redirectLogin = (req, res, next) => {
    const { userId } = req.session;
    console.log(userId); // < Output: undefined
    if (!userId) {
        res.render('pages/index');
    } else {
        next()
    }
}

So my weird question, if i assign value from DB which is integer and to test that i have if statement i get req.session.userId = 1, but when client is redirected its req.session.userId = undefined.
But if i assign value manually with that test line it works and server issues cookie and i can visit my site with no problems...
Am i doing something wrong?

A:

You are missing the fact that the callback to .findOne() is asynchronous and non-blocking.  That means that your request handler returns first and THEN, sometime later (after the res.redirect() has already been sent), the callback gets called.  So, the callback is too late for the redirect.  Instead, you need to do the res.redirect() inside the callback:
// POST services
app.post('/login', (req, res) => {
    const loginData = req.body;
    db.users.findOne({ username: loginData.uname }, function (err, doc) {
        if (err) {
            console.log(err);
            res.sendStatus(500);
            return;
        }
        req.session.userId = doc.id;
        if(doc.id === 1) console.log("True"); // < Output: True
        console.log(req.session.userId); // < Output: 1
        res.redirect('/plan');
    });
});

Depending upon what session store you're using, you may also have to save any changes to your session before you redirect.


Lewis Acid-Activated Reactions of Silyl Ketenes for the Preparation of α-Silyl Carbonyl Compounds.
Silyl-substituted ketenes are attractive molecular building blocks due to their stability and ease of storage, as opposed to unstable alkyl and aryl ketenes. To better understand the reactivity of silyl ketenes and, in turn, their use in the preparation of highly functionalized small molecules, the reaction of silyl ketenes with different nucleophiles was studied. The addition of alcohol, amine, or thiol nucleophiles to the central carbon of silyl ketene, followed by proton transfer afforded α-silyl ester, amide, or thio-ester, respectively. Catalytic amounts of Lewis acid greatly increase the rate of the reaction, and the impact of nucleophile, Lewis acid, and silyl substituent are evaluated. The small molecules produced from these reactions give insight into the use of silyl ketenes as building blocks for complex molecular structures.


Methylphenidate has positive hypocholesterolemic and hypotriglyceridemic effects: new data.
Many psychotropic drugs may affect plasma lipids profile and their metabolism, with carbamazepine being the best known among them. Methylphenidate is a piperidine derivative structurally related to amphetamines and acts as a central nervous system stimulant. Its effect on lipid metabolism has not been investigated. The authors evaluated how methylphenidate affects the lipid profile in the plasma of patients diagnosed as having attention-deficit hyperactivity disorder (ADHD). All consecutive patients undergoing treatment for ADHD at the Adolescent Psychiatric Clinic (2003-2007) were enrolled. Blood samples for total cholesterol, low-density lipoprotein cholesterol (LDL-C), high-density lipoprotein cholesterol (HDL-C), triglycerides, apolipoprotein A, apolipoprotein B, and lipoprotein (a) (Lp(a)) were collected before starting treatment and after 3 months of continuous treatment. Forty-two patients (22 men), median age 16, participated. The median total cholesterol count decreased by 9 mg/dL (P<.0002), LDL-C decreased by 5.0 mg/dL (P<.016), and triglycerides decreased by 8.0 mg/dL (P<.016). Changes in the levels of HDL-C, apolipoprotein A, and apolipoprotein B were nonsignificant, and Lp(a) levels decreased by 2.0 mg/dL (P<.0007). Methylphenidate improves the lipid profile by decreasing total cholesterol, triglycerides, LDL-C, and Lp(a).


280 S.E.2d 288 (1981)
STATE of West Virginia
v.
Robert W. CRITZER.
No. 14674.
Supreme Court of Appeals of West Virginia.
July 17, 1981.
*290 Marvin L. Downing and Jerry D. Moore, Frankling, for Critzer.
Chauncey H. Browning, Atty. Gen., Charles G. Brown, Deputy Atty. Gen., Charleston, for State.
*289 PER CURIAM:
Robert Wilson Critzer appeals from an April 16, 1979 final order of the Circuit Court of Pendleton County, overruling his post-trial motions and sentencing him to confinement in the penitentiary upon a jury verdict finding him guilty of obtaining money by false pretenses in violation of W.Va.Code, 61-3-24.
Critzer contends the trial court erred in: (1) admitting an in-court identification of the defendant in view of the unduly suggestive pretrial identification procedures employed by law enforcement authorities; (2) refusing to grant his motion for a mistrial predicated on the inflammatory and prejudicial statements by the prosecuting attorney to the jury during closing argument; and, (3) overruling his motion for a judgment of acquittal based on the insufficiency of the evidence. We reverse the conviction and grant a new trial because of prosecutorial misconduct in closing argument. We affirm the trial court's rulings on the identification issue and do not address the question of the sufficiency of the evidence.
On the afternoon of January 12, 1979, Masel Byrd, the victim of the false pretense, received a telephone call at his residence from an individual who identified himself as Mr. Wilson, a private investigator employed by the Pendleton County Bank. Mr. Byrd was advised that money was being embezzled from his savings account by an employee of the bank, and it was requested that he assist the bank in apprehending the embezzler by immediately withdrawing $2,400.00 in particular denominations, which was to be promptly picked up at Mr. Byrd's residence by one of the bank's investigators who had been called in from out of state to assist in the investigation. Mr. Byrd agreed to cooperate, immediately went to the bank, withdrew the money as requested, and returned home. A short time later, Mr. Byrd received a second telephone call from the man identifying himself as Mr. Wilson and shortly thereafter a man posing as a bank investigator came to the Byrd home, obtained the $2,400.00 from Mr. Byrd and left.
On the afternoon in question Jed Sponaugle, an eighteen-year-old Pendleton County youth, was working in his father's store. Sponaugle testified that a light blue, late model Cadillac pulled into the church lot, turned around, and drove off. Immediately thereafter he saw a man walking up the street in the direction of the Byrd residence. Because it was very unusual to see a new Cadillac in this rural community, Sponaugle testified that he was led to pay particular attention to its movements. The Cadillac, with Virginia license plates, passed by the store at least a half dozen times, twice parking in the church lot next to the store. The second time the Cadillac stopped in the church parking lot Sponaugle spotted a man getting into the car. A short time later Sponaugle saw the car for the last time, heading east with three occupants.
Fifteen days later on January 17, 1979, Sponaugle was shown photographs of several persons. He selected the photograph of the defendant as possibly being the driver of the Cadillac but was unable to make a positive identification. He also identified the man he saw entering the car in the church parking lot as one Albert Kanney, who was a resident of Virginia.
*291 Eleven days later on February 6, 1979, Sponaugle was brought to a Pendleton County Magistrate's Office to determine if he could identify Critzer as the driver. The defendant was handcuffed and was accompanied by three or four police officers at this "showup." Sponaugle positively identified Critzer as the driver. He testified that his identification was independent of the photographs and the prior confrontation. The defendant's motion to suppress was overruled, and Sponaugle made an in-court identification of the defendant.
Critzer's defense at trial was alibi. He was a resident of Winchester, Virginia when the crime was committed. He and his wife, and two other witnesses, a Mr. and Mrs. Finch, testified that he was in West Agusta, Virginia, assisting the Finch family in moving their residence on the day the crime was committed. On cross-examination the defendant admitted being an acquaintance of Albert Kanney, the man who was identified by Mr. Byrd as being the individual who received the $2,400.00, and who was also identified by Sponaugle as being the individual who was picked up in the church parking lot. He also admitted knowing of an individual who owned a late model Cadillac. The prosecution's theory of the case was that Critzer was the man who drove the car and telephoned Mr. Byrd identifying himself as an investigator by the name of Mr. Wilson. The prosecution argued that the defendant selected the surname Wilson because that was his middle name which he could easily remember.
We first consider the issue that requires us to reverse and remand for a new trial: the remarks of the prosecuting attorney during closing argument. Critzer contends that the prosecutor's remarks were not kept within the evidence and were made to inflame the jury and to induce a guilty verdict warped by prejudice. For its part, the State relies on the long and well-established rule that prosecutors are entitled to great latitude in closing arguments and it is only where improper remarks are clearly prejudicial or result in manifest injustice that reversal is proper. Syl. pt. 2, State v. Brewster, W.Va., 261 S.E.2d 77 (1979), quoting in part, Syl. pt. 1, State v. Dunn, W.Va., 246 S.E.2d 245 (1978); see also, Syl. pt. 8, State v. Reppert, 132 W.Va. 675, 52 S.E.2d 820 (1949), quoting, Syl. pt. 6, State v. Allen, 45 W.Va. 65, 30 S.E. 209 (1898); Syl. pt. 7, State v. Lewis, 133 W.Va. 584, 57 S.E.2d 513 (1949).
In State v. Boyd, W.Va., 233 S.E.2d 710 (1977), we discussed the role of a prosecuting attorney in a criminal case and emphasized that:
"The prosecuting attorney occupies a quasi-judicial position in the trial of a criminal case. In keeping with this position, he is required to avoid the role of a partisan, eager to convict, and must deal fairly with the accused as well as the other participants in the trial. It is the prosecutor's duty to set a tone of fairness and impartiality, and while he may and should vigorously pursue the State's case, in so doing he must not abandon the quasi-judicial role with which he is cloaked under the law." Syl. pt. 3, State v. Boyd, W.Va., 233 S.E.2d 710 (1977).
A prosecuting attorney has a duty not to make statements concerning facts not in evidence or not inferable from the evidence. As early as 1931, in State v. Moose, 110 W.Va. 476, 158 S.E. 715 (1931), this Court reversed a robbery conviction because the prosecutor's closing argument was not based on the evidence. The Court found the prosecuting attorney engaged in "palpable misconduct" rather than mere intemperance of speech. Id. at 477, 158 S.E. at 716. In the sole Syllabus, we held:
"An attorney for the state may prosecute vigorously as long as he deals fairly with the accused; but he should not become a partisan, intent only on conviction. And, it is a flagrant abuse of his position to refer, in his argument to the jury, to material facts outside the record, or not fairly deducible therefrom."
Similarly, in State v. Bragg, 140 W.Va. 585, 87 S.E.2d 689 (1955), this Court recognized its duty to caution prosecuting attorneys of this State against the use of their *292 positions in the trial of criminal cases, where the prosecutor in argument to the jury had given his opinion as to how the killing occurred without evidence of record on the issue justifying the remarks. The Court concluded the prosecutor's actions, even if no other error had occurred in the case, would have constituted reversible error. See also, Syl. pt. 2, State v. Kennedy, W.Va., 249 S.E.2d 188 (1978); T.C.R. VI (1963).
Closely related to the rule forbidding argument not based upon the evidence is the strict prohibition against a prosecuting attorney interjecting his personal opinion in the trial of a case. At the very least since this Court adopted the American Bar Association's Code of Professional Responsibility,[*] effective July 1, 1970, it has been improper for a prosecutor in this State to assert his personal opinion as to the justness of a cause, as to the credibility of a witness, or as to the guilt or innocence of an accused. This rule does not, however, prevent a prosecutor from arguing any position based on his analysis of the evidence. In Syllabus Point 3 of State v. Brown, 104 W.Va. 93, 138 S.E. 664 (1927), we held that counsel for the State ordinarily should not characterize an accused as a criminal. In Syllabus Point 3 of State v. Vineyard, 108 W.Va. 5, 150 S.E. 144 (1929), we held it was error for the prosecutor to express his belief in the veracity of a defense witness.
Upon careful consideration of all the facts and circumstances presented in this case, we are of the opinion that the prosecuting attorney's closing argument violated the basic principles just discussed, and that the defendant was prejudiced by the remarks and denied a fair trial. The prosecutor injected his personal opinion as to the guilt of the defendant, asserted his belief in the honesty, sincerity, truthfulness, and good motives of his witnesses, while attacking the honesty and veracity of the defendant's witnesses. He compared the defendant to a vulture and appealed to local prejudice by indicating the defendant came to West Virginia to victimize dumb hillbillies. On several occasions during the course of the argument he pointed to and directly addressed the defendant. He also argued facts not in evidence. For example, he suggested that Mrs. Finch used some of the money obtained by the false pretense to take ski trips to Showshoe, and he argued that defendant had never worked a day in his life. Defendant's testimony on this latter point was to the contrary. The prosecutor's manifest purpose could only have been to inflame the minds of the jury in order to gain a conviction based on emotions rather than evidence. The defendant made objection throughout the course of closing argument and requested the trial court to grant a mistrial based on the prosecutor's remarks. This was sufficient to preserve the point for appeal. The trial court denied the motion for a mistrial and either overruled or failed to rule on any of the defendant's objections made during the course of the argument. No instructions were given to the jury telling them the prosecutor's comments were improper and that they should disregard them. While we do not wish to characterize the State's evidence in support of a conviction, it is fair to say that it was not overwhelming.
Critzer also contends that the trial court erred in not suppressing Sponaugle's in-court identification. The standard of law applicable here is set forth in Syllabus Point 3 of State v. Casdorph, W.Va., 230 S.E.2d 476 (1976):
"In determining whether an out-of-court identification of a defendant is so tainted as to require suppression of an in-court identification a court must look to the totality of the circumstances and determine whether the identification was reliable, even though the confrontation procedure was suggestive, with due regard given to such factors as the opportunity *293 of the witness to view the criminal at the time of the crime, the witness' degree of attention, the accuracy of the witness' prior description of the criminal, the level of certainty demonstrated by the witness at the confrontation, and the length of time between the crime and the confrontation."
Although it is clear that the pretrial show-up procedure employed in this case was unnecessarily suggestive given the fact that there was no emergency, we conclude, under the totality of the circumstances, that the pretrial identification procedures were not so impermissibly suggestive as to give rise to a very substantial likelihood of irreparable misidentification. Neil v. Biggers, 409 U.S. 188, 93 S.Ct. 375, 34 L.Ed.2d 401 (1973). The evidence adduced in the in camera hearing on the motion to suppress the in-court identification shows that Sponaugle had an ample opportunity to observe the defendant and that his attention was drawn to the defendant because it was unusual for a new Cadillac with out-of-state license plates to drive up and down the street in Franklin, West Virginia. The witness was certain of his identification upon the confrontation in the magistrate's office, and the length of time between the crime and the confrontation was only approximately thirty days. The witness testified that his in-court identification was based on his observation of the defendant near the scene of the crime, independent of his pretrial identification.
While it is a fact that the witness gave no prior description of the driver of the car prior to the photographic array and the confrontation, thus affording no basis for a comparison to gauge the reliability of the identification, we are not persuaded that a due process violation has occurred in view of the other factors present in the case establishing the reliability of the identification. The witness, through a photographic array, was able to identify Albert Kanney, an acquaintance of the defendant who also resided in Virginia, as the man who got out and back in the Cadillac in the church parking lot. The victim, Mr. Byrd, corroborated the witness' identification of Kanney by identifying him as the man who came to his house representing himself as an investigator to whom he gave the $2,400.00. Certainly the fact that the witness could identify Kanney indicates his identification of the defendant was reliable. In sum, under all the circumstances, we find no substantial likelihood of misidentification and thus the trial court did not abuse its discretion in admitting the testimony.
For the foregoing reasons, we reverse and remand for a new trial.
Reversed and remanded; new trial awarded.
NOTES
[*]  DR 7-106(C)(4) provides that a lawyer shall not:

"Assert his personal opinion as to the justness of a cause, as to the credibility of a witness,... or as to the guilt or innocence of an accused; but he may argue, on his analysis of the evidence, for any position or conclusion with respect to the matters stated herein."


Kalachakra traditional Tibetan incense is purely hand prepared from highly flavored medicinal herbs and other precious substances. The combination of genuine scented substances makes the Kalachara Incense richer and superior quality then other incenses. Their incense is totally absent of choking and camphor smell and is also no-habit forming. Generally the Tibetan incense is used for Puja offering and purification, but it is also use as an airfreshner which keeps one's surrounding flavored with good scent.