Forty years ago, playgrounds were downright scary. Everything was made of metal. The slides were so hot they'd burn the skin right off your thighs. Kids would go flying off of those spinning contraptions, or perch precariously 10 feet in the air on monkey bars with rock-hard earth or concrete underneath.They don't make them like they used to, and that's a good thing. But a recent study by the Centers for Disease Control and Prevention finds that emergency departments still see more than 20,000 children ages 14 and younger for playground-related traumatic brain injury each year. As the weather warms up and trips to the park become frequent, take a moment to familiarize yourself with the risks of playground equipment and injury prevention strategies.
Some of the top equipment associated with injuries are climbers, swings, slides and overhead ladders, according to the National Program for Playground Safety. The U.S. Consumer Product Safety Commission has come up with playground hazards you should watch out for when taking your kids to the park.
Learn the scope of playground-related injuries in the U.S.


text:
/*
 * 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.
 */
package com.addthis.hydra.data.filter.closeablebundle;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import com.addthis.bundle.core.Bundle;
import com.addthis.bundle.util.AutoField;
import com.addthis.bundle.value.ValueArray;
import com.addthis.bundle.value.ValueObject;

import com.clearspring.analytics.stream.frequency.CountMinSketch;

import com.google.common.io.ByteStreams;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
 * This closeable bundle filter applies a limit using the count-min sketch data structure.
 * If the input is a scalar value then this filter returns true if it accepts the input. If
 * it rejects the input then that field is removed from the bundle and the filter returns false.
 * If the input is an array then this filter removes values that do not need the limit criteria
 * and always return true.
 *
 * @user-reference
 */
public class CloseableBundleCMSLimit implements CloseableBundleFilter {

    public enum Bound {
        LOWER, UPPER;
    }

    private static final String KEY_SEPARATOR = "&";

    @Nonnull
    public final AutoField[] keyFields;

    @Nonnull
    public final AutoField valueField;

    @Nullable
    public final AutoField countField;

    public final String dataDir;

    public final int cacheSize;

    public final boolean rejectNull;

    public final int limit;

    /**
     * The value to return if the filter removes the item from the bundle.
     * Only used if the input is a scalar. If the input is an array then
     * always return true. Default value of parameter is false.
     */
    public final boolean failReturn;

    /**
     * Optionally specify the depth of the sketch.
     * If 'confidence' is specified then ignore this value.
     */
    public final int depth;

    /**
     * Confidence that the error tolerance is satisfied.
     * If 'confidence' is specified then ignore 'depth' parameter.
     * Expressed as a fraction.
     */
    public final double confidence;

    /**
     * Width of the sketch in bits.
     * Either 'width' or 'percentage' are required.
     */
    public final int width;

    /**
     * Maximum error tolerated as percentage of cardinality.
     * Either 'width' or 'percentage' are required.
     */
    public final double percentage;

    @Nonnull
    public final Bound bound;

    private final CMSLimitHashMap sketches;

    private final int calcWidth;

    private final int calcDepth;

    @JsonCreator
    public CloseableBundleCMSLimit(@JsonProperty(value = "keyFields", required = true) AutoField[] keyFields,
                                   @JsonProperty(value = "valueField", required = true) AutoField valueField,
                                   @JsonProperty("countField") AutoField countField,
                                   @JsonProperty(value = "dataDir", required = true) String dataDir,
                                   @JsonProperty(value = "cacheSize", required = true) int cacheSize,
                                   @JsonProperty("rejectNull") boolean rejectNull,
                                   @JsonProperty("failReturn") boolean failReturn,
                                   @JsonProperty("width") int width,
                                   @JsonProperty("depth") int depth,
                                   @JsonProperty(value = "limit", required = true) int limit,
                                   @JsonProperty("confidence") double confidence,
                                   @JsonProperty("percentage") double percentage,
                                   @JsonProperty(value = "bound", required = true) Bound bound) {
        if ((width == 0) && (percentage == 0.0)) {
            throw new IllegalArgumentException("Either 'width' or " +
                                               "'percentage' must be specified.");
        } else if ((width > 0) && (percentage > 0.0)) {
            throw new IllegalArgumentException("Either 'width' or " +
                                               "'percentage' must be specified.");
        } else if (confidence < 0.0 || confidence >= 1.0) {
            throw new IllegalArgumentException("'confidence' must be between 0 and 1");
        }
        this.keyFields = keyFields;
        this.valueField = valueField;
        this.countField = countField;
        this.dataDir = dataDir;
        this.cacheSize = cacheSize;
        this.rejectNull = rejectNull;
        this.failReturn = failReturn;
        this.width = width;
        this.depth = depth;
        this.limit = limit;
        this.confidence = confidence;
        this.percentage = percentage;
        this.bound = bound;
        this.sketches = new CMSLimitHashMap();
        int cWidth = width;
        int cDepth = depth;
        if (cWidth == 0) {
            cWidth =  (int) Math.ceil(Math.E / percentage);
        }
        if (confidence > 0.0) {
            cDepth = (int) Math.ceil(-Math.log(1.0 - confidence));
        }
        calcWidth = cWidth;
        calcDepth = cDepth;
    }

    @Override public synchronized void close() {
        try {
            for (Map.Entry<String, CountMinSketch> entry : sketches.entrySet()) {
                writeSketch(entry.getKey(), entry.getValue());
            }
        } catch (IOException ex) {
            throw new UncheckedIOException(ex);
        }
    }

    @Override public boolean filter(Bundle row) {
        StringBuilder sb = new StringBuilder();
        for (AutoField keyField : keyFields) {
            Optional<String> optional = keyField.getString(row);
            if (optional.isPresent()) {
                if (sb.length() > 0) {
                    sb.append(KEY_SEPARATOR);
                }
                sb.append(optional.get());
            } else if (rejectNull) {
                return failReturn;
            }
        }
        return updateSketch(row, sb.toString(), valueField.getValue(row));
    }

    private synchronized boolean updateSketch(Bundle row, String key, ValueObject valueObject) {
        CountMinSketch sketch = sketches.get(key);
        if (valueObject == null) {
            return failReturn;
        }
        if (valueObject.getObjectType() == ValueObject.TYPE.ARRAY) {
            ValueArray array = valueObject.asArray();
            Iterator<ValueObject> iterator = array.iterator();
            while (iterator.hasNext()) {
                ValueObject next = iterator.next();
                updateString(next.asString().asNative(), sketch, iterator, row);
            }
            return true;
        } else {
            return updateString(valueObject.asString().asNative(), sketch, null, row);
        }
    }

    private boolean updateString(String input, CountMinSketch sketch, Iterator<ValueObject> iterator, Bundle bundle) {
        long current = sketch.estimateCount(input);
        switch (bound) {
            case UPPER:
                if (current > limit) {
                    removeElement(iterator, bundle);
                    return failReturn;
                } else {
                    updateCount(input, sketch, bundle);
                }
                break;
            case LOWER:
                if (current < limit) {
                    removeElement(iterator, bundle);
                    updateCount(input, sketch, bundle);
                    return failReturn;
                }
                break;
        }
        return true;
    }

    private void removeElement(Iterator<ValueObject> iterator, Bundle bundle) {
        if (iterator != null) {
            iterator.remove();
        } else {
            valueField.removeValue(bundle);
        }
    }

    private void updateCount(String input, CountMinSketch sketch, Bundle bundle) {
        long myCount = 1;
        if (countField != null) {
            myCount = countField.getLong(bundle).orElse(0);
        }
        if (myCount > 0) {
            sketch.add(input, myCount);
        }
    }

    private void writeSketch(String key, CountMinSketch sketch) throws IOException {
        byte[] data = CountMinSketch.serialize(sketch);
        ByteArrayOutputStream byteStream =
                new ByteArrayOutputStream(data.length);
        GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
        try {
            zipStream.write(data);
        } finally {
            zipStream.close();
            byteStream.close();
        }
        Path parent = Paths.get(dataDir);
        Path path = Paths.get(dataDir, key + ".gz");
        Files.createDirectories(parent);
        Files.write(path, byteStream.toByteArray());
    }

    private class CMSLimitHashMap extends LinkedHashMap<String, CountMinSketch> {

        CMSLimitHashMap() {
            super(cacheSize, 0.75f, true);
        }

        @Override
        public CountMinSketch get(Object key) {
            try {
                CountMinSketch sketch = super.get(key);
                if (sketch == null) {
                    ByteArrayInputStream byteStream = null;
                    GZIPInputStream zipStream = null;
                    try {
                        Path path = Paths.get(dataDir, key + ".gz");
                        if (Files.exists(path)) {
                            byte[] data = Files.readAllBytes(path);
                            byteStream = new ByteArrayInputStream(data);
                            zipStream = new GZIPInputStream(byteStream);
                            sketch = CountMinSketch.deserialize(ByteStreams.toByteArray(zipStream));
                        } else {
                            sketch = new CountMinSketch(calcDepth, calcWidth, 0);
                        }
                    } finally {
                        if (zipStream != null) {
                            zipStream.close();
                        }
                        if (byteStream != null) {
                            byteStream.close();
                        }
                    }
                    put(key.toString(), sketch);
                }
                return sketch;
            } catch (IOException ex) {
                throw new UncheckedIOException(ex);
            }
        }

        protected boolean removeEldestEntry(Map.Entry<String, CountMinSketch> eldest) {
            try {
                if (size() > cacheSize) {
                    String key = eldest.getKey();
                    CountMinSketch value = eldest.getValue();
                    writeSketch(key, value);
                    return true;
                } else {
                    return false;
                }
            } catch (IOException ex) {
                throw new UncheckedIOException(ex);
            }
        }
    }

    public static class CloseableBundleCMSLimitBuilder {
        private AutoField[] keyFields;
        private AutoField valueField;
        private AutoField countField;
        private String dataDir;
        private int cacheSize;
        private boolean rejectNull;
        private int limit;
        private boolean failReturn;
        private int depth;
        private double confidence;
        private int width;
        private double percentage;
        private Bound bound;

        public CloseableBundleCMSLimitBuilder() {}

        public CloseableBundleCMSLimitBuilder(CloseableBundleCMSLimit source) {
            this.keyFields = source.keyFields;
            this.valueField = source.valueField;
            this.countField = source.countField;
            this.dataDir = source.dataDir;
            this.cacheSize = source.cacheSize;
            this.rejectNull = source.rejectNull;
            this.limit = source.limit;
            this.failReturn = source.failReturn;
            this.depth = source.depth;
            this.confidence = source.confidence;
            this.width = source.width;
            this.percentage = source.percentage;
            this.bound = source.bound;
        }

        public CloseableBundleCMSLimitBuilder setKeyFields(AutoField[] keyFields) {
            this.keyFields = keyFields;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setValueField(AutoField valueField) {
            this.valueField = valueField;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setCountField(AutoField countField) {
            this.countField = countField;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setDataDir(String dataDir) {
            this.dataDir = dataDir;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setCacheSize(int cacheSize) {
            this.cacheSize = cacheSize;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setRejectNull(boolean rejectNull) {
            this.rejectNull = rejectNull;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setLimit(int limit) {
            this.limit = limit;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setFailReturn(boolean failReturn) {
            this.failReturn = failReturn;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setDepth(int depth) {
            this.depth = depth;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setConfidence(double confidence) {
            this.confidence = confidence;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setWidth(int width) {
            this.width = width;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setPercentage(double percentage) {
            this.percentage = percentage;
            return this;
        }

        public CloseableBundleCMSLimitBuilder setBound(Bound bound) {
            this.bound = bound;
            return this;
        }

        public CloseableBundleCMSLimit build() {
            CloseableBundleCMSLimit closeableBundleCMSLimit =
                    new CloseableBundleCMSLimit(keyFields, valueField, countField, dataDir,
                                                cacheSize, rejectNull, failReturn, width,
                                                depth, limit, confidence, percentage, bound);
            return closeableBundleCMSLimit;
        }
    }

}

redpajama_set_name: RedPajamaGithub


"We have a beautiful lake, and we want to make sure every (homeowner) comes out and enjoys it," said Steve Duis, a 10-year resident and one of six members of the community's social committee. The committee plans events for Davis Lake HOA members throughout the year.
The fishing tournament offered prizes and certificates for first fish caught, smallest and largest fish, and most fish in four age categories: age 2-5, 6-10,11-15, and 16 and older. Every participant received a certificate.
Not only was the tournament fun and family oriented, it was an educational experience for those new to the community and to fishing.
Resident fishing "professional" Joe Fass gave a demonstration on how to fish, which included tying knots, baiting a hook, casting and reeling in your catch. Fass has participated in several tournaments.
"I've been fishing most of my life," he said." "When I was a kid, my father got me hooked on fishing, and I've just always enjoyed doing it."
Fass and the social committee also provided tournament participants with a handout with casting tips and the types of fish found in the lake.
The lake is stocked with four types of fish (large-mouth bass, perch, sunfish and bluegill) and is serviced by local company Foster Lake Management. "They manage the health of the lake (such as) adding lily pads and maintaining fish population," said Duis. The lake is catch-and-release, which lessens the cost and need for repopulation.
The amenities Davis Lake Community offers, such as the lake, are what drew many of the residents to the neighborhood. "There are only about 50 homes on the lake, but the amenities, lake, pool, tennis courts, are open to all the members of our HOA," said Duis.
Bob Bird, a 16-year resident, said, "We like the lake a lot, and the pool. There are a lot of people that have a good time here."
Being with family and neighbors was the highlight of the day for most participants.
"The best part of the tournament is spending time with my kids and family for Father's Day," said Frank Lorio, proud father of two daughters.
Anne Frances Lorio, 10, liked "helping people with the fish" most. She caught eight fish during the tournament. Katie Wilkowski, 10, was also excited to go on her first fishing excursion and being with her dad, Eric, and sister.
"I caught only one, but it was a really big one," Katie said.


TTA is delighted to receive ISO 9001 re-accreditation once more.
Transport Training Academy isn't just passionate about training; we're also totally committed to supporting, embedding and promoting equality, diversity and safeguarding in every part of our training. We also take compliance and quality management seriously, that's why we always aim to comply with all current ISO standards and keep up-to- date with all procedural changes that take place in this ever-evolving arena.
So we're pleased to announce that Transport Training Academy has once again passed its ISO audit with flying colours and received ISO 9001 re-accreditation.
Well, ISO 9001 is a Quality Management Standard, designed for all organisations – large or small – and covering all sectors, including charities and the voluntary sector. It's the world's most popular ISO standard with over 1 million certifications issued. ISO 9001 aims to help organisations become more structured and efficient, and helps businesses meet legal and regulatory requirements which benefit the community, improve operational efficiency and improve customer satisfaction.


LANSING, Mich. (AP) — The number of measles cases in Michigan has reached 41, including the first reported in Washtenaw County.
The Michigan Department of Health and Human Services updated the numbers Monday with two additional cases. Thirty-nine cases have been confirmed in Oakland County.
Authorities are trying to determine possible exposure sites in Washtenaw County in southeastern Michigan. They're also urging people again to get vaccinated if they haven't received the vaccine in the past. Measles is highly contagious and is spread by personal contact and through the air.
The state considers the vaccine to be highly effective and safe. A single dose protects about 95% of children. After two doses, almost 100% are immune.
The number of measles cases in Michigan is the highest since 65 in 1991.


04 FebShould my Facebook profile be named after my business?
People want to do business with people. The whole point of entering the social networking realm is to make personal connections and build your business. While brand recognition is important, it is not as important as connecting with your customers and prospective customers.
When I look at a Facebook profile and see a business name, I feel like the person behind the page is hiding behind their logo. It does not convey that trusting feeling that would make me jump to do business with you.
My advice is to create a personal profile and then create a page or a group around your business or products and services. You are not your business. You have other interests that you can share with your customers. You can tell by my profile that I like snowmobiling, own a motorcycle, have kids, etc… That makes me "human" to the people who will approach me for web consulting. If I solely focused on NewWard then many of the connections I have made would have never come to fruition.
Be you first – sell second and always be genuine.
I am Eric Stranburg that's who I am. :) Facebook fan pages are key to branding.
Eric - Fan pages invite people to connect with you and keep track of your work... still have to be used with care :) !
I agree. Care needs to be taken and a plan should always be implemented. Facebook has switched over the Business pages to match more closely the Homepage. I am not a fan because it seems to add clutter to the once simple and streamlined page. Great care and restraint should always be observed especially when dealing with a brand and Facebook.


As part of her plans to lift the status of young ladies in the society, Queen Judith Nzubechukwu Orisaekeziem (Adaimo) will be hosting all Imo Beauty Queens in a programme tagged 'The Queens Diary' on Saturday, September 15, 2018.
The event which is a summit for both reigning, past and intending beauty queens in Imo State, according Queen Judith is part of her desire to redefine, reshape and reinforce the public image and advance the societal values of the present and successive generations of Imo Damsels.
"I believe their words will make participants at summit leave better than when they came. We want our ladies to understand what they have in them; but them to be strong enough to work for what they want, because strategic hard work will make them transmit the aura of a queen", she said.
The event is packaged in in collaboration with the Reach Media (Radio/Television) and powered by the Office Of The Special Assistant On Entertainment To The Governor Of Imo State.
With Imo State First lady, Ugonneoma Nkechi Rochas Okorocha expected at the event as the Mother of The Day, Makbere Marian (Author of 'Crown Factor' and Miss Tourism Nigeria Queen 2012) and Pastor Ada Ezeka of the Family Life will be among the guest speakers.
Other guest speakers are Mrs Uloma Nwosu (MD, The Reach Media) and Prof Edna Njoku, a versatile resource person and Senior Lecturer, Federal University of Technology, Owerri.
'The Queens Diary' is scheduled to hold on Saturday, September 15, 2018 at the Freedom Hall, Freedom Square (Old Warehouse Junction), Owerri, Imo State by 1:00pm Prompt.


BOTNET : All You need to Know About | How to Detect and Prevent it ?
Cyber attackers and criminals use Botnet networks for a variety of purposes, but the most common one is to use your computers for processing power. The most common use of a botnet network is for email spamming, using them for denial of service attacks, data mining, crypto mining, data theft, spreading virus, malware, trojan, adware, etc. Before you get your PC infected by botnet virus, let us get to know what Botnet really is and how to prevent your PC from it.
1 What is a Botnet Attack?
A Botnet is basically a big network of computers which are connected and compromised in such a way that the total control over those computers is in the hand of a hacker or an attacker. Each individual computer which is affected by this Botnet is known as a bot, which is a part of the big Botnet network. So, now the question arises when does a PC become a Bot? When does a PC become a part of big Botnet network?
Its simple, your PC will become a part of Botnet army if it gets infected by some malware which was originally created by some hacker in order to recruit computers to join his/her Botnet army. This malicious malware is a tiny program which circulates through your entire PC and allows the attacker to use and control your PC remotely without the concern of PC owner. The people who control these botnet networks go by the name of Bot herders or usually Bot masters.
As we said above that botnets are used by criminals and hackers. Now the question arises in your mind is how? How can you possibly make use of hundreds or thousands of PC via a remote control? Hackers use their Botnet networks for a number malicious activities. The most common of them are Web browser hacking, carry out attacks, stealing information, sending spam, overloading servers, click fraud, mine cryptocurrencies etc.
Botnets can impact you in several ways. Your PC might start opening random websites; it will become slow and unresponsive, etc. Cybercriminals and hijackers use botnets networks to create a zombie network. This zombie network might have thousands or even millions of computers interconnected via botnet malware.
This zombie network is capable of large-scale Distributed Denial of Service (DDoS) attacks, some large-scale spam campaign, or other types of cyber attacks. In some cases, the remote control of these botnets is in the hands of other criminals. These botnets are then combined together to build even a larger network. These Botnets are being sold as a rental or outright sale in black markets in deep web or dark web. Spammers take full advantage of these Botnet networks as it becomes very easy for them to spam advertisement or pull up a large-scale spam campaign.
Detecting a Botnet is a hard task. Botnet malware is designed to be silent and operates without coming in the eyes of the user. However, there are few symptoms which you look for in order to find whether your PC is a part of Botner or not.
High Traffic for outgoing SMTP traffic.
Unexpected popups here and there while you're working or browsing the web.
Slow computing power with a high CPU usage.
So you know what the symptoms of Botnet computers are. Now we are going to discuss some ways so that you can prevent your PC from Botnet networks.
Network baselining: You should keep a keep eyes on your incoming and outgoing network. Any kind of irregular network is the sign of Botnet activities.
Software patches: Always update your PC software, especially the anti-virus programs as soon as they release any security update.
Vigilance: PC users should be trained to keep their machine protected from any unwanted risks such as bot networks, DDoS attacks, spamming etc.
Anti-Botnet tools: Install a goof Anti-Botnet tool which can keep track of your PC and will figure out if your PC is part of a Botnet.
So, Guys, We have already discussed about How to detect if you are infected from a Botnet network. So its time to remove that Botnet malware from your PC. The best way of doing is to install some Botnet remover tool or using a security software with a built-in botnet removal functionality. Keep your PC safe!
Next articleHow To Track Your Child's Snapchat ?


Contact us now to discuss our special offers that are available this season.
We can discuss your needs at a time and place suitable for you, whether its day or night, on the phone or at your home.
Pests only need 1/64 of an inch to enter your home.
Establish barriers at entry points and migrations paths.
Clean webs, wasp nests, and egg sacks down from eaves and overhangs.
Pests are an annoyance! They persistently and systematically invade your home looking for food, water and shelter. Once indoors they pose serious health risks to you and your family and can damage your most valuable investment.
After being in the pest control service industry for years, we decided to break the mold. We decided that our true value to our customers was summarized in two words: green and clean. With that vision in mind, we started EcoShield Pest Control to give consumers the chance to experience the bliss of pest-free living in a safe, effective, and convenient manner!
Unlike some pest exterminators, EcoShield's Home Protection Plan combines the most innovative pest management methods and the safest products to drive pests out and keep them out for good! We provide a free pest inspection for your convenience as well.
At EcoShield, we understand: It's good to be bug free.
Every tech at this company has been wonderful to work with!
Love that it's a local company and they serve the community with a smile!
I've got to say [they] went above and beyond the call of duty with my pest control needs!


Collector Vehicles Archives - DeKok Insurance Group, Inc.
Jon here. Joy and I have been looking forward to sharing this post with you. Although I enjoy looking at classic cars, Joy really enjoys them. So, I'll let her tell you the story.
Joy here. I met Keith Schwartz in Jon's office when he stopped in to talk about some insurance. Jon told me that Keith owned a truck I'd like to hear about so I asked. Last night, Keith and his wife Sheryl shared Earl with us.
This might just be the coolest truck ever.
I took notes while Keith shared Earl's history. In 1979 this blue 1951 Chevrolet pickup was wasting away in a junkyard. Keith's brother purchased the truck for $150 thinking he'd use it for parts on another truck he owned. Instead, he decided to drive the rusted, blue one. While in college, the brothers drove it through the harsh North Dakota winters, pulling other vehicles out of ditches, because this Chevy could and did.
Over the years, the brothers sold the truck – to each other, keeping it in the family. In 1991, Keith bought it because he said, "I loved it from the time we pulled it out of the junkyard." He then took it down to pieces, and it stayed that way for sixteen years. In 2000, he started the restoration process, which he completed in 2009. Standing beside Earl, I realized when Keith says he restored him, he means every single piece of that truck has passed through his hands and is in excellent condition. Earl didn't get a surface restoration – he is fully restored.
Last night, when Jon parked across the street from Keith and Sheryl's house, my heart beat a little faster. Is it possible to be smitten by a pickup? It seems so.
After pulling the pickup out of the junkyard, the brothers found some letters that read, Earl, on the truck by the box where it couldn't be seen unless you opened the door. Although it was likely the owners name, it immediately became the truck's name.
When I stepped in front of the truck, it felt like he smiled at me. And yes, I smiled back. I couldn't help myself. He's such a happy looking guy and it's contagious.
Then Keith showed me the interior – this old boy is classy inside and out!
This is my favorite picture of Earl.
All of that makes perfect sense to me. Earl is a Chevy classic, but in a way, he's in class by himself.
I'll hand this back to Jon for now. It was really nice visiting with Keith and Sheryl, and it was nice meeting Earl. As we pulled away, I looked at the pickup again and thought, "That is honestly one cool truck!" Today writing this post, I feel the same way. He is.
Jon here. Do you own a classic car? Call for a quote. Earl is insured with Hagarty – one of the best insurers of classic and antique cars.
Tell your family members and friends about your positive experience with DeKok Insurance Group, Inc. If they call for a quote and tell us you sent them, YOU will receive a $20 gift card from us.
Hagarty specializes in collector/vintage cars and boats. They're a company for car guys run by car guys.
Because they focus on classics, they are experts on valuation (their guys name is Rob) – which allows them to offer clients what they call Guaranteed Value Coverage. Their interest in classic vehicles includes knowledge on restoration, dealerships, storage facilities, and museums.
Hagerty's Plus Roadside Assistance is an essential for collector owners. It covers flatbed towing, plus unlimited service for lockouts, battery replacements, and more – 24/7 in the U.S. and Canada.
I'm proud to represent this quality company here at DeKok Insurance Group. So far, I've been able to save my clients with collector vehicles money and I've given them superior coverage working with Hagarty.
If you've got a classic car or boat and want to know more, call me at 507-226-8121.
It's a lot easier to enjoy the ride when you know you're covered.
Serving MN clients for almost 30 years, I specialize in home, auto, umbrella, business, and life insurance.
If you have any questions regarding your insurance or insurance in Minnesota, please call me at 507-226-8121.


Major Ingrown Toenail Treatment Tutorial - Terrible Toenails Pedicure By Professional Pedicurists. Real reasons behind toenail injuries are high heels that can cause a number of foot problems, yet most women aren't willing to give their shoes the boot. Ingrown toenails are among the most common problems that result from high heels. This condition, also known as onychocryptosis, occurs when the toes compress together making the big toenails grow into the skin.
Ripped Toenail Transformation - From Gross To Great!


text:
console.log('running proxy-config.js');

module.exports = {
  // Calls to /api/foo will get routed to
  // http://nielsen-bluemix-orchestration-app.mybluemix.net/foo.

  '/api/testDialogs': {
    target: 'http://nielsen-bluemix-orchestration-app.mybluemix.net/api/testDialogs',
    changeOrigin: true,
  },
  '/api/documents': {
    target: 'http://nielsen-bluemix-orchestration-app.mybluemix.net/api/documents',
    changeOrigin: true,
  },
  '/api/testAlchemy': {
    target: 'http://nielsen-bluemix-orchestration-app.mybluemix.net/api/testAlchemy',
    changeOrigin: true,
  },
  '/api/testDashDB': {
    target: 'http://nielsen-bluemix-orchestration-app.mybluemix.net/api/testDashDB',
    changeOrigin: true,
  },
  '/api/testNaturalLanguageClassifier': {
    target: 'http://nielsen-bluemix-orchestration-app.mybluemix.net/api/testNaturalLanguageClassifier',
    changeOrigin: true,
  },
  '/api/': {
    target: 'http://nielsen-bluemix-orchestration-app.mybluemix.net/api/',
    changeOrigin: true,
  }
};


text:
NVIDIA GeForce FX, or "Cinema show started".
Main hero - NV30 starring as a GPU of the new generation GeForce FX.
Secondary main hero - R300 as RADEON 9700 PRO.
128 bit DDR II memory clocked at 1 GHz as a main villain.
DirectX 9.0 shaders and cinematographic effects as arguments.
Progressive technologies of memory optimization and full-screen anti-aliasing in the science-fiction role of defenders. of the main hero.
Popular synthetic actors of finished and scheduled full-length 3D movies are also taking part in this movie.
Around the scenario: "Run, Industry, run"!
The NVIDIA's GPU codenamed NV30, so long-awaited and one of the most arguable GPUs, was announced on November 18, 2002. It was coupled with the announcement of a new marketing name of GeForce FX. First NVIDIA was going to give a new name to a new trademark to emphasize its importance but then it turned out that it was impossible to refuse its mark. According to the public-opinion polls, the GeForce brand is known to much more people than the company's name NVIDIA is. It's like with Pentium. The parallel with Intel, which is a recognized locomotive of the IT industry is well suitable here as at the moment NVIDIA is a flagship on the 3D graphics ocean, like 3dfx was in its time, a creator of the first really successful hardware 3D solution. Symbolically, while working on the NV30 the developers used a lot of ideas of the 3dfx's project codenamed Mojo which failed to be completed.
No secret that the GeForce FX is an incarnation of a so called flexibly programmable graphics architecture, i.e. a graphics processor. Therefore, this chip should be called GPU, but on the other hand, this term was earlier used for less flexible solutions of the previous generation of accelerators (let's call it the DX8 generation: NV2x, R200 etc.). Let's glance at the transient process from a fixed architecture to flexibly programmable ones:
DX7/NV1x/R100 brought configurable pixel stages.
DX8/NV2x/R200 brought vertex shaders and limited pixel shaders based on the same shaders.
DX9/NV3x/R300 added normal vertex shaders with controllable command streams, software-controlled pixel shaders with arbitrarily positioned commands.
This is an "evolutionary revolution" whose current stage is not completed yet. There is one or maybe several stages coming in the near future:
DX10/NV4x/R400 - vertex and pixel shaders with totally controlled command streams without any limitations in size.
A fully symmetric scheme of a programmable GPU as an array of full-featured shader processors without any predetermined architectural division into pixel and vertex shaders tessellating or selecting texture units.
Well, we'll see what we will see. But two latter steps can bring in here much more than two DX versions both because of Microsoft and a guileful intent of graphics chip makers.
On the other hand, while in terms of such evolutionary layout the current stage looks expected, users and programmers can take it as a revolutionary period as it provokes a switchover to utilization of capabilities of flexible programming of accelerators. Big flexible pixel shaders, even without the command stream control, are able to bring to PC an earlier unreachable visual level making a much greater jump compared to the first attempts of the previous generation clamped by the awkward assembler code of shaders and a limited number of pixel instructions. Quality, rather than quantity, can win this time, and the epoch of DX9 accelerators can become as significant as the arrival of the 3dfx Voodoo. If you remember, the Voodoo wasn't conceptually the first. But it did provoke a quantitative jump of accelerators, which then turned into a qualitative jump of development of games for them. I hope this time the industry will be given a powerful spur caused by the possibility to write complex vertex and pixel shaders on higher-level languages.
Let's leave aside the issue concerning a revolutionary nature of DX9 solutions which are so much spoken about among sales managers. Just must say that while the revolutionary character of the solution as a whole is yet to be proved, the revolutionary character of the separate technologies of the GeForce FX is undoubted.
The accelerators are gradually approaching common general-purpose processors in several aspects:
Considerable increase of clock speeds
The rough force is now being replaced by fine optimization algorithms and approaches
Computational aspect is in the forefront
Developed system of the general-graphic-purpose commands.
Support of several universal formats (types) of data.
Possible superscalar and speculative execution.
Complexity and flexibility of programs are getting less limited.
The accelerators are striding toward CPUs and they have already outpaced average general-purpose processors in the number of transistors or peak computational power. The issue of convergence depends only on time and flexibility. CPUs are also nearing them by increasing their performance, especially in vector operations, and soon they will be able to fulfill yesterday's tasks of graphics acceleration. Moreover, the degree of brute force parallelism of CPU is growing up as well - just remember the HT or multicore CPUs. The direct confrontation is not close, but it will definitely take place, and primarily between trendsetters in one or another sphere rather than between the classes of devices (the outcome will be called CPU (or CGPU :). Wallets of users are being fought for now, and graphics in this sphere doesn't lose to CPUs.
Before going further I recommend that you read (if you haven't yet) the following key theoretical materials:
3dfx Tribute
Matrox Parhelia 512 and DirectX 9
3dlabs P10 and OpenGL 2.0
ATI RADEON 9700 and DirectX 9
ATI RADEON 9700 PRO
Now we are finishing the digression and turning to our main hero - GeForce FX.
GeForce FX: leading role in focus
Straight away: the key specifications of the new GPU:
0.13 micron fabrication process.
125M transistors
3 geometrical processors (each exceed the specs of the DX9 VS 2.0)
8 pixel processors (exceed the specs of the DX9 PS 2.0 markedly) with one texture filtering unit on each
8 texture filtering units which provides up to 8 fetched and filtered results per tact, but can process (fetch and filter) up to 16 bilinear textures per tact.
AGP 3.0 (8x) system interface
128 bit (!) DDR II interface of the local memory
Effective 4-channel memory controller with a crossbar
Unique techniques of local memory optimization including a full frame buffer compression, with color (compression ratio 4:1) and depth information compressed
Tile optimization: caching, compression and Early Cull HSR
Support of precise integer-valued formats (10/16 bit per component) and precise floating-point formats (16 and 32 bits per component - also known as 64 and 128 bit color) for the textures and frame buffer
Through accuracy of all operations - 32 bit floating-point arithmetic
New selectable algorithm of adaptive anisotropic filtering makes the speed fall down smaller
Anisotropic quality up to 128 discrete samples per one texture fetch
New AA modes - MSAA 8x (DirectX/OpenGL) and hybrid MS/SSAA 6x (in DirectX only)
Frame buffer compression makes possible to reduce a performance drop markedly with AA enabled
Two integrated 10 bit RAMDACs 400 MHz
Interface for external TV-Out chip
Integrated into GPU TV-Out
Three TDMS interfaces for external DVI interface chips
Three DVI interfaces integrated into GPU (1600x1280 maximal resolution with one and 2048*1534 with two in pair)
Power consumed by the chip based on the .13 technology is comparable to the requirements of the AGP 3.0 specification. Therefore, it's possible to make cards without external power.
And now look at the block diagram of the GeForce FX:
Functions of the blocks:
Cache controller, Memory controller, Crossbar - the block controls exchange and caching of data coming from the local memory of GPU and AGP system bus.
Vertex Processors - geometrical processors which execute vertex shaders and emulate a fixed T&L. They fulfill geometric transformations and prepare parameters for rendering and for pixel processors.
Pixel Processors - execute pixel shaders and emulate pixel stages. They shade pixels and make requests for texture fetch units.
Texture Fetch & Filtering & Decompression Units. They implement fetching of certain values of certain textures required by pixel processors.
Texture & Color Interpolators - they are interpolators of texture coordinates and color values calculated as output parameters in the vertex processor. These units calculate for each pixel processor its unique input parameters according to the position of a pixel it is shading.
Frame Buffer Logic - the unit controls operation with the frame buffer including Frame Buffer Compression & Decompression, caching, Tile HSR Logic - so called Early Cull HSR, and MSAA Allocation and post processing of samples - the final filtering in FSAA modes (FSAA post-processor)
2D Core
Two display controllers, two RAMDACs and interfaces
Let's go through the main units of the new chip approximately in the same order as a usual data flow goes. Along the way we will comment on their functions, architecture (the basic one regarding the DirectX 9.0 and additional capabilities of the GeForce FX) and make small lyrical digressions.
Obviously, data the chip works with, programs and commands it processes are formed by the CPU with the help of drivers, and then they get into the graphics chip via a special graphics bus (AGP) which acts as a system interface. Take a close look at it:
As you can see, the program addresses the API quite often changing different parameters (in modern applications changing of parameters implies primarily establishment of new textures and shaders) and then it sends a buffer with geometrical data for drawing which is to be fulfilled by the accelerator using earlier defined shaders and textures. But API requests are not sent directly to the accelerator - it would be too prodigal. Different settings are accumulated by the driver in a special buffer in the system memory, and only when the time to draw a certain geometrical picture with them comes, the accelerator is given that buffer with saved settings (commands), a shader code and links to geometrical data to be drawn. Starting from this point of time the accelerator interprets the buffer itself adjusting its internal units and draws the geometry it was given selecting data from the local and/or system memory via the system interface (the geometrical data are often located in its memory, entirely or partially). The drivers do not wait for the accelerator to complete its work, they return management to the program and keep on collecting settings and commands in a new buffer. They will have to wait only if the request for drawing comes before the accelerator finishes the previous work.
By the way, it wouldn't be correct to call the data geometrical because they can have a flexible, set by the program, record format for each vertex. The record consists of a set of basic types of data - such as floating-point and integer values and vectors, color values etc. How these parameters are to be interpreted, which of them define geometrical coordinates of a pixel in space, which are the numbers of combined textures and what are texture coordinates or color values or other parameters of pixel shaders - all these issues are decided by the code of a vertex shader, by i.e. a programmer. You thus describe your internal formats of object presentation and program the accelerator so that it can interpret them correctly. The functions earlier fulfilled by CPUs are now put on the shoulders of a flexibly programmable processor.
In the GeForce FX the system interface is realized via an AGP bus and, in particular, its third version.
Let me sum up the differences and new features of the AGP 3.0 standard also known as AGP 8x in comparison to the AGP 4x:
Doubled bandwidth. Now it's 2.1 GB/s, and the effective clock speed equals 533 MHz:
AGP 4X AGP 8X
Bytes per transfer 4 (32 bits) 4 (32 bits)
Clock rate 266.67 MHz 533.33 MHz
Bus bandwidth 1.1 GB/sec 2.1 GB/sec
New capabilities of the isochronous data transfer (i.e. continuous transmission of data streams with guaranteed latency) which lets the accelerator know for sure that the parameters it needs will be supplied in time and it won't have to waste its time in null cycles.
The bus is entirely compatible (forward and backward) with cards of the previous version (AGP 2.0) and supports 2x and 4x modes within the 2.0 standard and 4x and 8x modes within the extended 3.0 standard. That is why new cards which will fully comply with the AGP 8x specification will be compatible with all mainboards with AGP 2x, 4x and 8x, and new AGP 8x boards will support cards with 2x and 4x provided that they comply with the AGP 2.0 or 3.0 specification. As we know, there are compatibility problems with earlier realizations of the AGP 8x (SIS 468, R300).
Optimization for more efficient AGP texturing.
Some rare and unpopular features of the 2.0 are excluded (they can be deleted without damaging compatibility).
Will the AGP 3.0 bring advantages for the accelerators of the latest generation? First of all, it depends on programs. Actually, new complex pixel shaders and nontrivial models of rendering and lighting increases both the number of used textures and their size and the number of parameters transferred with each vertex which describe properties of drawn materials. Besides, the geometrical performance of the new chip has markedly increased compared to the previous generation, which is also going to add requirements for the bandwidth of the system bus. But most modern applications use scenes of moderate complexity the textures for which can be fully put into the accelerator's memory. And geometrical data do not take more than a third of the bandwidth of the AGP 4x.
Cinematographic quality which is so much discussed these days in connection with the GeForce FX certainly must increase demands to the system bus as so highly detailed scenes can take gigabytes. The question is how soon it's going to arrive. Most likely, more than one generation will change before we can see a scene of quality and size comparable with today's popular synthetic movies executed on the hardware level. However it can be, but the AGP 8x support is necessary as the bandwidth of the AGP 4x is not sufficient anymore. It's also necessary to comply with the modern standards and to reduce delays (when addressing the accelerator) which is becoming a real enemy today.
There is nothing to worry about - the new AGP version will be enough for the GeForce FX. Probably, it is the last classical AGP in its present form - the next general-purpose graphics bus will probably be based on serial technologies developed within the frames of the 3GIO project.
Memory controller and local buffer
The unexpected decision of NVIDIA to use a 128bit memory bus coupled with the high-speed DDR II memory caused a lot of disputes. On the one hand:
It reduces cost and complexity of printed-circuit boards by a great margin.
It reduces cost and dimensions of the GPU package
DDR II memory has a more perfect interface, is less demanding and better protected from noise
DDR II memory has much lower typical latency and access time, which has an effect in case of complicated access scenarios. Besides, the curve of development of parameters of the DDR II memory looks more optimistic:
There is plenty of leeway for the next chip: even with the same memory the bus can be extended up to 256 bits.
1 GHz 128 bit DDR II memory has a lower peak physical throughput (16 GB/s) compared to the 256 bit DDR memory clocked at 600 MHz and higher used in other DX9 accelerators (about 20 GB/s for the RADEON 9700 PRO).
Graphics tasks form a quite sequential character of memory access, which make them less sensitive to its delays.
1 GHz DDR II memory will probably be more expensive and in greater demand than the classical DDR.
Nevertheless, I have no doubts that the experts from NVIDIA thought over their decision well. And they most likely had definite figures obtained in course of emulation or utilization of the test chips.
The strongest advantage is the memory optimization technologies. Using such technologies it's possible to easier reach an effective memory throughput comparable or even greater than that of 256 bit solutions. Further we will look into this question in detail.
The memory controller is based on the 4-channel scheme (4x32) typical of NVIDIA products, which showed excellent results on the chips of the previous generation. The internal caches of the chip are connected to 4 memory channels and the system bus by a full crossbar, like in the previous generation.
There are 4 main data streams formed when the chip's working - three for reading (textures, frame buffer, geometrical information) and one for recording (frame buffer). Besides, a part of or all geometrical information can come from outside via the system bus. A 4-channel memory controller suits best of all for such scenario - in case of two channels the performance will drop significantly and with more than 4 channels it won't raise much though the number of chip's outputs and complexity of the board will be much greater. In this respect it's interesting to take a look at the RADEON 9500/9500 PRO - in this configuration the R300 has only two working memory controllers, and it's quite possible that this factor is determining in its inferior performance. For cheaper versions of the GeForce FX it will be possible to have a less efficient memory but still 4 channels used in the 128 bit configuration.
From the system interface and local memory interface data proceed to the chip's internal caches - a geometry chip, a frame buffer chip and a texture chip. Then they go to respective units. Let's start with the geometry:
Vertex processors
The GeForce FX has three (!) independent vertex processors which fully comply (and even exceed) with the DX9 specification for vertex shaders 2.0. Even in current applications the geometrical performance of such tandem must be 2..3 times higher than that of the geometrical unit of the NV25 both thanks to the greater number of the processors and the higher core's clock speed. But that's not all.
Here is a general block diagram of the vertex processor of the DX9:
So, intermediate data are processed and stored in the floating-point format F32. At the input the shader's program has up to 16 4D vectors - the source geometrical data we were speaking about above. At the output we have a vertex position in the screen coordinates, a pixel size if sprites are involved, 8 vectors of texture coordinates and 2 vectors of color values which are then interpolated (while triangles are rendered) for each pixel. After interpolation values of these vectors will get into the pixel shader as input parameters. Besides, we have 256 constant vectors assigned from outside and 12 temporary general-purpose registers used for storing intermediate data. There are also 4 special registers - samplers which let the vertex shader select values from textures for using textures as displacement maps and other similar effects.
From this point of view a vertex processor reminds any other general-purpose processor. But what's about programmability? A shader is a program which controls a vector ALU processing 4D vectors. A shader's program can be 256 ops long but it can contain loops and transitions. For organization of loops there are 16 integer registers of counters I which are accessible from the shader only for reading, i.e. they are constants assigned outside in an application. For conditional jumps there are 16 logic (one-bit) registers B. Again, they can't be changed from the shader. As a result, all jumps and loops are predetermined and can be controlled only from outside, from an application. Remember that this is a basic model declared by the DX9.
Besides, the overall number of instructions which can be processed within the shader with all loops and branches/jumps taken into account is limited by 65536. What for such strict limitations? Actually, to meet such requirements the chip can do without any logic controlling execution of loops and jumps. It's enough to organize successive execution of shaders up to 665536 instructions and unroll all conditions and loops in advance in the driver. Actually, every time the program has its constants controlling branch and jump parameters changed, we have to load into the chip a new shader. The R300 uses exactly such approach. Exactly this approach lets us have only one set of control logic and a copy of vertex program shared by all vertex processors. And this approach doesn't make the vertex processor normal - we can't make on-the-fly decisions unique for each vertex taking into account criteria calculated right in the shader. Moreover, such unrolling of jumps and loops can make a process of replacement of the shader or its parameters controlling jumps quite demanding in terms of CPU resources. That is why ATI recommends to change vertex shaders as seldom as possible - the cost of such replacement is comparable to change of an active texture.
NVIDIA made a step further making vertex processors dynamically controlled. Each vertex processor of the GeForce FX has its own indicator of a current command and a set of logic controlling jumps and loops. Such processor is more complicated but more flexible in programming. We can use newly obtained computational results as determining parameters in loops and conditions as it's done in usual programming languages for usual general-purpose CPUs. We can say that the vertex processors of the GeForce FX advocate an individual approach to each vertex. :)
Such solution makes the chip more complicated but it also simplifies the work of programmers. For example, it's not necessary to divide an original model into several parts for loading or for modulation to process its different parts using different methods - one can implement necessary selection inside the vertex shader and use just one shader instead of three-four different ones. NVIDIA gives a good example in its documentation for developers. Moreover, it takes quite a lot of time to replace a vertex shader both because of checking and compilation, and significant latency of the system AGP bus. It's possible that it will be much more advantageous to use a big shader consisting of several dynamically switched algorithms than frequent changes of small and specialized shaders.
Besides, it's possible to use various optimizations, for example, to calculate light from a close source by one algorithm and from a far source by another algorithm - this will also let us save on performance. We can interrupt execution of a shader, for example, according to a certain condition, to make calculations more optimized.
It's interesting that the GeForce FX incorporates three vertex processors according to the number of pixels in a triangle, instead of four like in the ATI's product. It's clear that dynamic jumps made NVIDIA use additional transistors. Three processors can be a weak point and a quite balanced solution - we still don't have enough information on a performance of a separate vertex processor per unit of clock speed. Like in case of usual CPUs it can differ much in different solutions. The previous tests with synthetic applications showed that NVIDIA could make perfectly balanced products. Besides, a frequency of the core of the GeForce FX is noticeably higher than that of the RADEON 9700 PRO. In the practical testing we will see how balanced the new chip is and compare it with the ATI's products.
And right now let's take a glance at the comparison table of capabilities of the vertex processors:
1.1 base 2.0 base 2.0 (R300) 2.0 (NV30)
Input vectors 16 16 16 16
Output vectors and 4D interpolators 4+2 8+2 8+2 8+2
Temporary registers 12 12 12 16
Constants 96 256 256 256
Loops, max. no 16 16 64
Jumps and loops no beforehand beforehand Dynamically
Static instructions, max. 128 256 256 256
Fulfilled instructions, max. 128 65536 65536 65536
The parameters in bold type allow NVIDIA to speak about the support of shaders on the 2.0+ level.
Of course, the dynamic execution is desired. Sooner or later all shaders, both pixel and vertex, will get it as an obligatory requirement. But now, within this generation of accelerators and API, it's not clear how popular it's going to be with programmers. What if they will use the least common denominator (like it was with pixel shaders 1.4), i.e. the base version 2.0. I think it will be so in the near future. But this new solution of NVIDIA can be supported more widely in case of OpenGL where programmers have to write two versions of a code quite often.
Also remember that the set of instructions of vertex shaders in the DX9 was extended compared to the DX9, with normal trigonometric functions and conditional write and reorder instructions. It's interesting that realization of trigonometric functions in the GeForce FX is very quick - it takes the same time to calculate SIN or COS as a couple of additions (!). It seems that it operates with special matrix execution units together with big tables of constants.
Here are commands supported by the vertex processors of the GeForce FX:
Add and multiply (ADD, DP3, DP4, DPH, MAD, MOV, SUB)
Math (ABS, COS, EX2, EXP, FLR, FRC, LG2, LOG, RCP, RSQ, SIN)
Set On (SEQ, SFL, SGR, SGT, SLE, SLT, SNE, STR)
Branching (BRA, CAL, NOP)
Address Registers (ARL, ARR)
Graphics-oriented (DST, LIT)
Minimum/maximum (MAX, MIN)
One more curious peculiarity of the GeForce FX is realization of displacement maps. Actually the chip doesn't have a separate hardware unit controlling tessellation of N-Patches and displacement maps - there is just a possibility (which is beyond the vertex shaders 2.0) not only to use in the shader data selected from a texture but also record computational results of a vertex shader into a certain memory place which can be interpreted as a texture or a vertex buffer. This won't be open for developers and will be meant only for internal use, in particular, for realization of DM without a separate hardware unit. But in future DX versions it will be possible to record calculated data from a vertex shader into accelerator's memory, up to generation of an arbitrary number of new vertices necessary for support of arbitrary HOS on the shader level.
Pixel processors and texture units
First of all, let's again look at the logic diagram of a pixel processor in terms of basic requirements for the PS 2.0 DX9:
So, at the input we have 8 texture coordinates interpolated across the triangle surface (with perspective correction) and two interpolated color vectors. Originally, these vectors were calculated for each triangle vertex, but to obtain their values for each pixel rendered by a pixel shader we have to interpolate them depending on a position of a given pixel relative to the vertices. From the programmer's point of view these vectors can contain anything, not just texture coordinates and color. The pixel shader will define how to use them.
At the output we have up to 4 different color values (each being a 4D vector) recorded into different output frame buffers and one depth value which we can change and record. We have at our disposal 32 constant vectors and 12 temporary vector registers. This is how pixels shaders are arranged in the R300, according to the letter of the DX9 specification, except one extension used both in the R300 and in NV30 but still not mentioned in the DX9 documentation - we can use in the shader a calculated depth buffer value and an original color value of a given pixel for realization of our own blending or for making certain decisions.
In course of execution of a shader we can fulfill texture fetching, up to 16 different textures are available (the depth of nesting of dependent fetches mustn't exceed 4). For texture fetching there is a special command which indicates where to send the result, from which texture (one of 16 registers of samplers) and according to which coordinates data are to be fetched. Contrary to the previous generation this is a normal command of a shader and can be used in any place in any order. But the number of commands of fetching is limited - although the total length of a shader can reach up to 96 instructions, the number of requests to textures mustn't exceed 32 and number of other instructions mustn't exceed 64.
As we have 8 coordinates interpolated across triangles, we can't call these 16 textures normal in terms for the old accelerators. If earlier a TMU was a unit including both a mechanism of texture fetch and filtering and an interpolator of texture coordinates, now there are no such TMUs. Now we have two separate units - a set of interpolators and a set of units fulfilling texture fetching by request of a shader. Multiple effects need access to different textures according to equal coordinates or, for example, multiple fetches from one texture according to dynamically calculated coordinates, that is why such approach seems to be justified.
Contrary to a vertex processor which always works with the F32 data format, a pixel processor (like in R300 and in NV30) supports three formats- F32, F16 and integer I16 (R300) / I12 (NV30). The latter two formats are not just useful for compatibility with old shaders 1.x but also provide speed gains in calculations.
In the DX9 the system of commands of a pixel processor is similar to the system of commands of a vertex one:
Add and multiply (ADD, LRP, DP3, DP4, LRP, MAD, MOV, SUB)
Texturing (TEX, TXD, TXP)
Partial Derivatives (DDX, DDY)
Math (ABS, COS, EX2, EXP, FLR, FRC, LG2, LOG, NRM, POW, RCP,RSQ, SIN)
Graphics-oriented (DST, LIT, RFL)
Macros (SINCOS, CRS)
Pack (PK2H, PK2US, PK4B, PK4UB, PK4UBG, PK16)
Unpack (UP2H, UP2US, UP4B, UP4UB, UP4UBG, UP16)
Kill (KIL)
There are separate commands of texture access (fetch) and pack/unpack commands for storing nonstandard sets of scalar and floating-point variables in standard formats of textures and frame buffer. This is a good way to save on the memory's throughput and space taken by source data and shader's results when implementing complex effects.
Note that recording (modification) of depth values makes unjustified all HSR optimizations and attempts of early determination of visibility which boost up performance of modern accelerators. So, if you use or modify data on depth in the shader, the hardware early HSR will be disabled, and the overall rendering efficiency will fall down.
In the sphere of pixel shaders of the GeForce FX the requirements of the DX9 are exceeded again:
Input vectors 4+2 8+2 8+2 8+2
Output vectors 1 4+Z 4+Z 4+Z
Temporary registers 2 12 12 16/32*
Constants 8 256 256 Up to 1024/512**
Jumps and loops no no no no
Predicates no 12 12 64
Maximum depth of nested fetches 4 4 4 unlimited
Unique textures up to 4 16 16 16
Static instructions, up to (texture+arithmetic) 4+8 32+64 32+64 Up to 1024**
(*) 16 F32 registers or 32 F16 registers
(**) Each used F32 constant is worth two commands, i.e. the number of constants * 2 + the number of commands do not exceed 1024. Each used F16 or I12 constant is worth one command.
The GeForce FX is certainly very flexible here. But will that be needed for programmers for anything beside NVIDIA's demo programs?
But we have multiple "no's" exactly for the pixel shaders. First of all, the performance of commands drops down twice (at least) while processing floating-point data compared to integer data (this is a pure computational performance without accounting for losses caused by increased data volumes). A pixel processor of the GeForce FX can execute up to two integer and one floating-point command per clock, i.e. it acts as a superscalar processor in case of integer operations. This maintains an acceptable speed comparable with solutions using stages in case of execution of shaders 1.x.
Secondly, floating-point textures cannot be filtered (!). If we want to fetch bi- or trilinear filtered values from a texture stored in the floating-pint format we must program filtering in the pixel shader using for it 4 or 8 texture fetches and a dozen of computational instructions. This must cool down our striving for increased data precision (with calculations there is only double drop). Well, there are new capabilities, but we must wait for a new edition of the chip (NV35) or a next generation (NV40) to use them.
It's interesting that NVIDIA managed to realize texture fetching commands without any delays. Each texture fetching can be fulfilled at a clock even if the neighboring fetches are dependent and located near by. This can give the GeForce FX a considerable advantage over the R300 in case of complex shaders. Actually, the chip has a pool of 8 units for unpacking, fetching and filtering of textures. But at a clock it's possible to fulfill only one command of data fetching from a texture in each pixel processor, and we can get up to 8 textures per clock. But the units can fetch 8 discrete samples per clock, i.e. implement trilinear filtering without speeding down (like in the R300). But in case of bilinear textures the GeForce FX unit gets an advantage - such a scheme lets it fetch values of two different bilinear textures at a clock one of which will be directly sent to the chip and the other saved and delivered at the next stage. What for are such tricks? In a complicated scenario when fetching of simple bilinear textures are followed by a lengthy anisotropic filtering this can help increase the overall effectiveness of execution f a shader saving one clock. The time will show whether it's worth doing, but many scenes contain one or two textures which are quality-filtered by the anisotropy and several additional bilinear ones. That is why such scenario of economy mustn't be something unusual. In simple cases we get a similar picture:
R300 NV30
Bilinear filtering 8 textures per clock 8 textures per clock
Trilinear filtering 8 textures per clock 8 textures per clock
Minimal anisotropic settings 8 textures per clock 8 textures per clock
But the clock speed of the GeForce FX is higher, and secondly, in some combined systems when bilinear, anisotropic and trilinear textures take turns in one shader, the GeForce FX can have a certain advantage (potentially) over the RADEON 9700 at equal frequencies. But a real effectiveness of a dynamically configurable pool of texture units is yet to be studied. The main advantage will be the above mentioned lack of delays when fetching dependent textures. And here sample of the situation when GeForce FX fetch two bilinear and one anisotropic (16õ) textures in 3 tacts, for that R300 use 4 tacts:
Tact Fetch Filtering Return
1 2 bilinear 2 bilinear 1st bilinear result (2nd stored)
2 1 anisotropy (1st 8 samples) 1 anisotropy (first half) 2nd bilinear result
3 1 anisotropy (2nd 8 samples) 1 anisotropy (second half) anisotropy result
It's interesting that when working with traditional integer textures (8 bits per component) values are processed by an exponential function (gamma correction). An exponent value corresponds to the sRGB standard. It allows saving and editing correctly an image with a wider dynamic range, despite the 8bit data representation. This feature is default for the DX9 chips and integrated into the R300 and NV30. Below is an example (from ATI J) of using such gamma correction when rendering an image:
The right picture shows more typical lighting in a cathedral. And this picture was calculated using the gamma correction.
The speed of trilinear filtering is crucial for modern chips. NVIDIA did nothing cardinally new here - the NV30 keeps on using adaptive algorithms of full anisotropy inherited from the NV25. The developers say however that they made slight optimizations which can be enabled in the driver settings and allow for a certain performance boost without noticeable quality losses. However that can be but 16 texture units and a high core clock speed must tell upon the performance markedly. We'll see how frightful it can be for ATI products with their traditionally efficient anisotropy.
The NVIDIA's approach to realization of anisotropy primarily depends on computational resources of the chip and after that on the memory's bandwidth. ATI lays the most load on the memory using the algorithm based on RIP cards. Such approach was one more argument for a 256 bit bus for ATI and a 128 bit bus with a higher clock speed of the chip for NVIDIA.
Full-screen anti-aliasing and frame buffer compression
The most interesting ability of the GeForce FX is frame buffer compression, when both depth values and color values can be compressed. According to NVIDIA, the compression algorithm works without losses but this should be verified - how one can speak about a constant compression ratio of 4:1 in case of lossless compression? Either the compression ratio will vary (and then they specified its typical value) or there will be losses. However, with a good algorithm the losses can be pretty small. We'll prepare some tricky synthetic tests to find out that.
The buffer compression has a lot of advantages:
Quick cleanup of the frame buffer, like it was earlier possible for the depth buffer.
Memory bandwidth saving, especially together with usage of compressed textures.
At high resolutions and with triple buffering it will be possible to save on space in the local memory, making possible to house more textures and geometrical data unloading the AGP bus and increasing the overall performance.
It will increase effectiveness of using the available bandwidth of the local memory making the performance of a 128 bit bus comparable to competing 256 bit solutions.
By the way, the R300 also uses compression algorithms for color information in the frame buffer, but they are not so effective. But the main advantages with a good implementation of a frame buffer will be obtained with full-screen anti-aliasing! Remember the MSAA? No additional calculations are needed - all samples within the AA unit are formed from one result calculated by a pixel shader. The only factor that causes performance drops is a necessity to transfer forth and back a frame buffer which at 4x AA will be four times bigger. At the same time, in the 4x mode most AA units have two or even one unique color value. We certainly must use such an opportunity and code effectively information of such MSAA buffer by recording only available colors and a bit mask of their arrangement.
With the MSAA we can make up for the increase size of the buffer (maybe just a couple of percent of additional data will remain). Besides, the buffer will also be compressed by the general compression algorithm. So, the moderate modes of the MSAA are going to be almost costless (for example, 4x and 4xS) and higher settings are going to be very cheap in case of the GeForce FX. The advantage can be so considerable that it will be able to overlap the gap between NVIDIA and ATI products in the combined modes which are the most interesting for current and upcoming applications.
The GeForce FX also includes a new MSAA mode 8x, and a new hybrid SS/MSAA mode 6xS (this one only for DirectX). That is why the chip can record up to 8 MSAA samples from one value calculated by a pixel shader.
So, the developers of the GeForce FX counted mostly on the frame buffer compression, especially in the FSAA modes. In this respect, usage of the 128 bit bus can prove that the hope is justified.
Dressed-up hero: GeForce FX based reference card.
Here is a reference design of a card based on the GeForce FX:
It houses a connector of external additional power, one DVI, one TV-Out and one VGA connector. The Silicon Image chip controls the DVI interface while the Phillips chip works with TV-Out. Despite the TV-Out and DVI interfaces integrated into the GeForce FX this card uses a tried solution based on external interface chips. According to NVIDIA, when the integrated interfaces and the software are debugged the external interface chips will be removed. 8 128 MB 128 bit DDR II memory chips from SAMSUNG, 1 GHz of effective data transfer. The memory chips are located quite far from the chip - it seems that the 128 bit bus and improved interface characteristics of the DDR II allowed for a simpler layout. The chip is officially clocked at 500 MHz, but its future versions can have different frequencies (maybe even higher). The card can use a cooling system with external air intake and tap, which is advertised by OTES:
Distribution and return: conclusion by a film critic
I'm looking forward to the final scene knocking together the RADEON 9700 PRO and NVIDIA GeForce FX. The battle will take place on the arena of synthetic DX9 and real DX8/DX9/OpenGL tests. I think the most interesting scene is going to be in the extremely popular, though not finished yet, Doom III game. This game is able to influence the life of several generations of video cards of one or the other camp. NVIDIA has traditionally strong OpenGL drivers and a high clock speed of the chip, while ATI comes with a wide memory bus and a line of products which goes ahead the time. However, the preliminary data indicate that the game will have a computational character, which suits NVIDIA well.
And here are some figures:
Card RADEON 9700 PRO GeForce FX 5600
Core frequency 325 MHz 500 MHz
Effective memory frequency 620 MHz 1000 MHz
Memory bus bandwidth 256 bit 128 bit
Pixels/sec, max. 2.6 Gigapixels 4 Gigapixels
Texels/sec, max. 2.6 Gigapixels 4 Gigapixels
Memory bandwidth 19 GB/s 16 GB/s
Claimed effective bandwidth 60 GB/s 60 GB/s
Vertex ops/sec 1.3 GigaOps (4D) 1.5 GigaOps (4D)
Pixel ops/sec 5.2 Gigaops (4D, I16) 8 Gigaops (4D, I12)
Note that the claimed effective memory bandwidths are equal! Well, we can't verify it as the memory optimization techniques can't be disabled. But we estimate the real efficiency of these algorithms as 1.5 times for ATI and 2.0 times for NVIDIA of a physical bandwidth in typical scenarios. That is why an effective bandwidth is probably about 28 GB/s for ATI and 32 GB/s for NVIDIA, which can provide at least a 30% gain for NVIDIA in typical applications.
Armed with these figures ATI plans on production of a chip clocked at 400..500 MHz started in the first half of 2003, which will be more affordable and not less efficient - RV350, and in the second half of 2003 we will see a .13 chip running at 500-600 MHz (R400), a future competitor against an optimized version of the NV30 (let's call it NV35). In the first half of 2003 NVIDIA will introduce two new players - NV31 and NV34 whose niche can be estimated by experienced users. The chips will be based on the mastered 0.13 fab process and use units developed for the NV30. Besides, it's possible they will release NV30 versions working at a higher core speed - 550 or even 600 MHz - in the NVIDIA's lab the first chips were running error free at such frequencies.
From a user's point of view, the RADEON 9700 (not PRO) can be a very strong rival for the NVIDIA's solutions as it carries an attractive price/performance ratio for users who are not totally indifferent to games. In the sphere of mid-range and budget DX9 accelerators - RADEON 9500/9500 PRO there are no products from NVIDIA, but a bit later we will see the NV3X solutions.
The higher-level language for shaders in the DX9 will tell positively upon development of products supporting new technologies. Many programmers didn't want to deal with shaders because of too complicated development and debugging of an assembler code. The NVIDIA's initiative of creation and maintenance of an open compiler of a higher-level language for shaders (CG) and an interpreter of files similar to DX9 effects (CG FX) will have a positive effect as well. Both products have source texts available and support both APIs (DirectX and OpenGL) which will make works loads simpler for OpenGL programmers. There are plugins for popular 3D graphics packets which export models and materials in the form comprehensible for the CG FX.
First samples of the GeForce FX based cards will be available in December, the mass deliveries of the chips will start in January, and in February the cards will be widely available for users. The start price is not fixed yet but in the first weeks it will be within the range from $399 to $499 depending on the situation on the memory market and a region.
Now, take seats in the cinema hall - the block-buster promises to be thrilling! Moreover, I think that it will remain unpredictable till the end ...
I wonder when we can have such graphics in a real-time mode on our screens...
Aleksander Medvedev (unclesam@ixbt.com)
Write a comment below. No registration needed!

redpajama_set_name: RedPajamaCommonCrawl


text:
I Love the 90s Tour
The next edition of I LOVE THE 90's TOUR invites attendees to reminisce about the trend-setting decade with some of the most iconic, indelible names in rap, hip hop and R&B. The tour features performances by iconic '90s artists including Vanilla Ice, All 4 One, Young MC, and The Funky Bunch. Audiences can expect to hear chart-topping hits like "Ice Ice Baby", "I Swear", "I Can Love You Like That", "Bust A Move", "Good Vibrations", "Wildside" and many more.
Shanise26@yahoo.com


And so we find ourselves, once again, at Augusta. The point at which, for many sports fans, the golf season truly starts. For every player in the field, it's the week they have circled in their calendar as soon the previous year's Masters concludes, and the tournament around which they plan their schedule every season. For golf bettors, it's a gem of a tournament also – a limited field event with a whole heap of no-chancers, a huge back book of course form, every player legitimately trying, and many companies falling over themselves to offer you concessions for their business.
For exchange players, this presents opportunities to gain yourself some excellent EV bets at minimal risk utilising the lay function. Of course, if you're happy to ride out the variance, you'll also find some great value in the outright market, with industry best prices.
What a time to be a punter.
So what is it that makes the Masters so special? The course, the history, the many traditions, the exclusivity of the event both for players and spectators – it all of the above combined but for me, it's the reverential tones in which the event is discussed that creates that additional buzz. Take any top player and they'll have talked of their love of Augusta at some point, and whenever a lesser light wins a tournament they immediately talk about the thrill of getting an invite to Augusta.
The chance to be written into the annals of history is present for every player this week, and there is seemingly a narrative for every player in the field. The task we have is pinning down which one will be the story that fits best so that we're collecting our winnings on Sunday evening as the victor is being handed his green jacket by Patrick Reed.
It hardly feels necessary to talk too much about the course given how popular it is in the golfing world but suffice to say, it's a brute. The beautiful azaleas and snooker-baize like fairways belie a test that requires all facets of a player's game to be functioning at 100%. The course, host since 1934, has been lengthened out to just under 7500 yards, so the ability to shift the ball off the tee is a pre-requisite, particularly since the four par 5s are really the only scoreable holes on the track, though length alone won't get the job done.
The common consensus is that a draw is the go-to shot for Masters champs, though in this day and age most players can shape shots both ways. Regardless, approach play is critical as the severely undulating bentgrass greens are running up to 14 on the stimpmeter, so the ability to hit a lot of greens and control your spin is critical as repeatedly scrambling is not going to lead to a particularly pretty scorecard. Ultimately, players will make bogeys but the players who control the big numbers will win out. As such, the key stats I'm looking for this week are a strokes-gained approach, par 4 scoring, bogey avoidance and driving distance.
The field for the Masters seems to get smaller and smaller each year and this year we've got just 87 starters. Thankfully for us, roughly half of those players are priced at 501.00 or higher so we can reasonably discount them from our equations. Indeed, over the past 10 renewals of the event, we've seen just one three-figure winner (Charl Schwartzel in 2011, 101.0) and an average price of 41.0 for the winner. Granted, this is a small sample but the Masters is just not an event that most players in the field can win and having scanned the market, I couldn't find anyone outside of the top 25 in the market that I genuinely felt was a value bet.
In spite of his love of Augusta, Ollie is happy to dismiss Jordan Spieth's chances this week.
With that said, of those 25 there were a fair few with reasonably claims – Spieth, DeChambeau, Scott, Woods and Mickelson were the easiest to dismiss at their prices – but I eventually settled on three of the top 15 for my bets.
Though Rory McIlroy's claims are obvious given his excellent start to the season, the price of 8.6 about a man who has struggled to get over the line for the past couple of years seems a touch too short, especially at an event which leaves little room for error. Instead, I want to side with a much more prolific winner at a slightly more workable price and prefer Dustin Johnson, as he bids to win his first green jacket.
The big South Carolinian was going off nearly half the price for this two seasons ago before an untimely slip down some stairs derided his bid before the off. His form leading in this year is not dissimilar as he has already won twice and recorded three other top 10 finishes in his past six stroke play events and I think he's entitled to be a couple of points shorter given he's been the most consistent player in the field over the past five seasons.
As long as Dustin Johnson can avoid any dodgy Augusta stairs, Ollie feels that DJ will be right in the mix this week.
Top 10s in his past three Masters starts shows that the course suits just fine and he's the ideal statistical fit, ranking 8th in par 4 scoring, 10th in strokes gained approach and 4th in bogey avoidance to go along with his prodigious length off the tee.
For a man of his talent, it's a mystery how he still only has the one major title but I'm firmly of the belief number 2 will be this week.
My next best is another prolific winner on the PGA Tour, who has a game perfectly suited to Augusta, Justin Thomas. The nine-time Tour winner has an improving form line at the Masters reading T39-T22-T17 but that doesn't tell the whole story as he sat 5th at halfway last year, having fired a blistering second round 67, only to stall over the weekend. His aggressive style of golf means that no golf course is immune to his talents and when on song, his iron play is arguably the best in the world. Having started the season in impressive fashion with four top 10 finishes his first five events, he's hit a little lull with just two non-descript top 35s in his past two outings.
Despite a quiet few weeks, Justin Thomas's Augusta form in recent years has been trending upwards.
In truth, that's likely just served to length his price for an event where he's entitled to be a few points shorter so I'm not too worried about his short term form. He ranks 4th in strokes gained approach, 8th for par 4 scoring and 30th in bogey avoidance so could well outrun his 20.0 price and bag a second major.
My final selection is Japanese superstar, and Brad Allen favourite, Hideki Matsuyama. The 27-year-old looked to have the world at his feet a couple of years ago having bagged five PGA Tour wins in 3 seasons and multiple top 10s across all majors. However, he suffered from a wrist injury that derailed his progress and only really recaptured that previous form at the beginning of this season. However, since the turn of the year, he's been one of the most consistent ball strikers in the world, ranking 2nd for strokes gained approach and 18th in driving distance.
Hideki Matsuyama aka one of the finest ball strikers in the game.
His (big) struggles have been with the flat stick but every player at Augusta is going to be struggling on the greens, and having two putts for par is obviously way more advantageous than having one, having missed the green on approach. He ranks 22nd for bogey avoidance and 38th in par 4 scoring this season and, looking back to his best, it's no stretch to see him improving upon his Masters best of 5th in 2015. Four consecutive top 20 finishes here should definitely become five and I expect him to be well in the mix come Sunday.


Custom solutions for preventing shipping to areas where it is not permitted. This capability can be particularly important for vendors selling live items (plants, animals) or items subject to regulation (alcohol, firearms, adult oriented content).
I have developed a number of these kinds of modifications over the years, and this page is designed to show you what's possible for your store.
Cost: Based on your requirements, starting at $300. This is not a plugin; it's custom software developed for your needs to your specifications. Before I can give you a final estimate, we need to discuss your needs.
A customer who sells livestock has to configure each product according to which states restrict delivery of those products. The restricted states are checked and shown at the top.
One customer who sells live plants faces specific restrictions from a few states on parts of his inventory.
Mechanisms to communicate the legal restrictions to customers will depend on the complexity of the rules.
This vendor has state by state exclusions on specific products.
This ammunition vendor chose a similar model because the wording was lengthy.
Copyright © 2003-2019 by Zen Cart Expert That Software Guy, Inc. This page last modified 04/15/19. Built with Bootstrap.


His rags-to-riches story is no less than a miracle and if it is made into a movie sometime later then it won't come as a surprise to us. 21 year old Virender Raika was born in a poor family and worked as a hawker to fund his studies. However, all the hardships he faced never stopped him from achieving his dreams.
The guy from Pehowa village in Kurukshetra has been offered a whopping 4.85 crores annual package by software giant Microsoft recently for his extra-ordinary anti-hacking software. Although he had cleared JEE entrance, Virender could never study in IITs owing to financial constraints.
"After my father who works as a laborer fell sick, I had to take up the job of a hawker. I soon realized that the money won't suffice. So, I started giving Physics tuitions," said Virender Raika. He was a class x topper.
"The idea to develop an anti-hacking system struck me while I was watching a movie. I saw a girl hacking into a system and then I thought why not develop a system that has a foolproof security. There are ways to hack into a system but no permanent way to secure it. So by working on various cyber theories, I made an anti-hacking system," stated the tech-wizard.
This tech-wizard was giving a demo of his anti-hacking project to a group of expert hackers at Microsoft's office in Hyderabad when Peter Klein, the Chief Financial Officer of the Microsoft, offered him a job straightaway after being impressed by his demo online. Virender Raika will join Microsoft in November as he is currently pursuing B.Tech from IGNOU.
"I want to open my own company in India. I want to do something for my country. We are so dependent on the US for technology. I want to turn the tide," Virender said. His father Gyan and Mother Shinder had no idea about what their son has achieved.
"We both are illiterate. We just know that Virender has got a job of 4.5 crore and companies from China and Japan are pursuing him," said Gyan Chand, Virender's father.


text:
package org.apereo.cas.support.x509.rest.config;

import org.apereo.cas.adaptors.x509.authentication.X509CertificateExtractor;
import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.rest.factory.RestHttpRequestCredentialFactory;
import org.apereo.cas.rest.plan.RestHttpRequestCredentialFactoryConfigurer;
import org.apereo.cas.support.x509.rest.X509RestHttpRequestHeaderCredentialFactory;
import org.apereo.cas.support.x509.rest.X509RestMultipartBodyCredentialFactory;
import org.apereo.cas.support.x509.rest.X509RestTlsClientCertCredentialFactory;

import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

/**
 * @author Dmytro Fedonin
 * @since 5.1.0
 */
@Configuration("x509RestConfiguration")
@EnableConfigurationProperties(CasConfigurationProperties.class)
@Slf4j
public class X509RestConfiguration {

    @Autowired
    private CasConfigurationProperties casProperties;

    @Autowired
    @Qualifier("x509CertificateExtractor")
    @Lazy
    private ObjectProvider<X509CertificateExtractor> x509CertificateExtractor;

    @Bean
    public RestHttpRequestCredentialFactory x509RestMultipartBody() {
        return new X509RestMultipartBodyCredentialFactory();
    }

    @Bean
    public RestHttpRequestCredentialFactory x509RestRequestHeader() {
        return new X509RestHttpRequestHeaderCredentialFactory(x509CertificateExtractor.getObject());
    }

    @ConditionalOnProperty(prefix = "cas.rest", name = "tls-client-auth", havingValue = "true")
    @Bean
    @RefreshScope
    public RestHttpRequestCredentialFactory x509RestTlsClientCert() {
        return new X509RestTlsClientCertCredentialFactory();
    }

    @Bean
    @RefreshScope
    @ConditionalOnMissingBean(name = "x509RestHttpRequestCredentialFactoryConfigurer")
    public RestHttpRequestCredentialFactoryConfigurer x509RestHttpRequestCredentialFactoryConfigurer() {
        return factory -> {
            val restProperties = casProperties.getRest();
            val extractor = x509CertificateExtractor.getObject();
            val headerAuth = restProperties.isHeaderAuth();
            val bodyAuth = restProperties.isBodyAuth();
            val tlsClientAuth = restProperties.isTlsClientAuth();
            LOGGER.trace("Is certificate extractor available? = [{}], headerAuth = [{}], bodyAuth = [{}], tlsClientAuth = [{}]",
                extractor, headerAuth, bodyAuth, tlsClientAuth);

            if (tlsClientAuth && (headerAuth || bodyAuth)) {
                LOGGER.warn("The X.509 feature over REST using \"headerAuth\" or \"bodyAuth\" provides a tremendously "
                    + "convenient target for claiming user identities or obtaining TGTs without proof of private "
                    + "key ownership. To securely use this feature, network configuration MUST allow connections "
                    + "to the CAS server only from trusted hosts which in turn have strict security limitations "
                    + "and logging. Thus, \"tlsClientAuth\" shouldn't be activated together with \"headerAuth\" "
                    + "or \"bodyAuth\"");
            }

            if (extractor != null && headerAuth) {
                factory.registerCredentialFactory(x509RestRequestHeader());
            }
            if (bodyAuth) {
                factory.registerCredentialFactory(x509RestMultipartBody());
            }
            if (tlsClientAuth) {
                factory.registerCredentialFactory(x509RestTlsClientCert());
            }
        };
    }

}