[% page.title = "Perl 5.14.0 Release Announcement" %]
The Perl 5 developer team is pleased to announce the Perl Release of 5.14.0
SHA-1 signatures for this release:
da5e991f9d4a6728eccfc190c5ddbed3c02a94fe perl-5.14.0.tar.bz2
7e2aab2101b087f6f2b9405b626a3f064c23693d perl-5.14.0.tar.gz
You can download this release from your nearest CPAN mirror or from: http://search.cpan.org/dist/perl-5.14.0/
You can find a full list of changes in http://search.cpan.org/~jesse/perl-5.14.0/pod/perldelta.pod
Perl 5.16 will be released in the spring of 2012. If you'd like to help shape Perl 5's future, please join us on the perl5-porters mailing list.
Perl 5.14.0 represents one year of development since Perl 5.12.0 and contains nearly 550,000 lines of changes across nearly 3,000 files from 150 authors and committers.
Perl continues to flourish into its third decade thanks to a vibrant community of users and developers. The following people are known to have contributed to this release:
Aaron Crane, Abhijit Menon-Sen, Abigail, Ævar Arnfjörð Bjarmason, Alastair Douglas, Alexander Alekseev, Alexander Hartmaier, Alexandr Ciornii, Alex Davies, Alex Vandiver, Ali Polatel, Allen Smith, Andreas König, Andrew Rodland, Andy Armstrong, Andy Dougherty, Aristotle Pagaltzis, Arkturuz, Arvan, A. Sinan Unur, Ben Morrow, Bo Lindbergh, Boris Ratner, Brad Gilbert, Bram, brian d foy, Brian Phillips, Casey West, Charles Bailey, Chas. Owens, Chip Salzenberg, Chris 'BinGOs' Williams, chromatic, Craig A. Berry, Curtis Jewell, Dagfinn Ilmari Mannsåker, Dan Dascalescu, Dave Rolsky, David Caldwell, David Cantrell, David Golden, David Leadbeater, David Mitchell, David Wheeler, Eric Brine, Father Chrysostomos, Fingle Nark, Florian Ragwitz, Frank Wiegand, Franz Fasching, Gene Sullivan, George Greer, Gerard Goossen, Gisle Aas, Goro Fuji, Grant McLean, gregor herrmann, H.Merijn Brand, Hongwen Qiu, Hugo van der Sanden, Ian Goodacre, James E Keenan, James Mastros, Jan Dubois, Jay Hannah, Jerry D. Hedden, Jesse Vincent, Jim Cromie, Jirka Hruška, John Peacock, Joshua ben Jore, Joshua Pritikin, Karl Williamson, Kevin Ryde, kmx, Lars Dɪᴇᴄᴋᴏᴡ 迪拉斯, Larwan Berke, Leon Brocard, Leon Timmermans, Lubomir Rintel, Lukas Mai, Maik Hentsche, Marty Pauley, Marvin Humphrey, Matt Johnson, Matt S Trout, Max Maischein, Michael Breen, Michael Fig, Michael G Schwern, Michael Parker, Michael Stevens, Michael Witten, Mike Kelly, Moritz Lenz, Nicholas Clark, Nick Cleaton, Nick Johnston, Nicolas Kaiser, Niko Tyni, Noirin Shirley, Nuno Carvalho, Paul Evans, Paul Green, Paul Johnson, Paul Marquess, Peter J. Holzer, Peter John Acklam, Peter Martini, Philippe Bruhat (BooK), Piotr Fusik, Rafael Garcia-Suarez, Rainer Tammer, Reini Urban, Renee Baecker, Ricardo Signes, Richard Möhn, Richard Soderberg, Rob Hoelz, Robin Barker, Ruslan Zakirov, Salvador Fandiño, Salvador Ortiz Garcia, Shlomi Fish, Sinan Unur, Sisyphus, Slaven Rezic, Steffen Müller, Steve Hay, Steven Schubiger, Steve Peters, Sullivan Beck, Tatsuhiko Miyagawa, Tim Bunce, Todd Rinaldo, Tom Christiansen, Tom Hukins, Tony Cook, Tye McQueen, Vadim Konovalov, Vernon Lyon, Vincent Pit, Walt Mankowski, Wolfram Humann, Yves Orton, Zefram, and Zsbán Ambrus.
This list is woefully incomplete as it is automatically generated from version control history. In particular, it doesn't include the names of the (very much appreciated) contributors who reported issues in previous releases that helped make Perl 5.14.0 better. For a more complete list of all of Perl's historical contributors, please see the AUTHORS file in the release tarball.
Many of the changes included in this version originated in the CPAN modules included in Perl 5's core. We're grateful to the entire CPAN community for their contributions.


Ecclesiastes 5:20
For he shall not much remember the days of his life; because God answereth him in the joy of his heart.


Did the 2016 Presidential election inspire long-time residents of New York City to vote?
Each dot below represents one voter in New York City that was registered to vote prior to the 2008
Presidential election. However, these voters did not participate in a Presidential election until 2016.
The median age of voters within selected groups is indicated by the green line.


MyDiary
Logout
View & Edit Entry
My mum's 50th birthday
11-07-2018 At 8:00am
we ate some cake and drank red wine!
Edit & Save Changes
New Entry


Toggle navigation
AWS User Pool Boilerplate
Readme
Login
Register
Verify
Restricted Page
Register
Email
Name
Password
Register


Planning a party, but don’t have anywhere to store your planning resources? Party Planner helps you track your party planning budget and progress. We offer a clean interface to store your budgets, lists, guests, theme, and date. No matter what your party needs are our mission is to help, by giving you easy to use solutions that make planning a party less stressful.


Dojo saves you time, delivers powerful performance, and scales with your development process. It's the toolkit experienced developers turn to for building superior desktop and mobile web experiences.
Dojo saves you time and scales with your development process, using web standards as its platform. It's the toolkit experienced developers turn to for building high quality desktop and mobile web applications.


Cilic-less Croatia sack their Davis Cup coach
Zagreb - Zeljko Krajan was on Saturday axed as Croatia Davis Cup team coach just nine days before the defending champions play the inaugural match in the finals, the Croatian tennis federation (HTS) said.
"After a joint meeting of senior HTS officials and players ... it was concluded that the squad will not attend the Davis Cup finals in Madrid under the leadership of coach Krajan," HTS head Nikolina Babic said in a statement.
The federation has "agreed with him (Krajan) to terminate cooperation," she said without elaborating on the reasons for the move.
Krajan, a 40-year-old former professional player, took over as the country's Davis Cup coach in 2012.
Croatia, who beat previous winners France in last year's final, face Russia in Madrid on November 18.
They will be also without former US Open winner Marin Cilic, who announced his withdrawal because of a knee injury on Thursday.
Cilic, world No 39, said that due his recurring knee injury he would have to undergo a "few minor interventions".
It would "keep me off the tennis court for a longer period and unfortunately means I will not be able to compete at the Davis Cup this month," he wrote on Facebook.
The 31-year-old was supposed to play in a squad of five Croatian players which includes Borna Coric, Mate Pavic, Ivan Dodig and Nikola Mektic.
Local media reported he would be replaced by veteran Ivo Karlovic, 40.
HTS and the players are to hold a press conference on Monday.
Davis Cup's new 18-team format has replaced the former World Group.
The nations have been split into six three-team groups, with the winners and two best runners-up advancing to the quarter-finals.
Russia and Croatia have been drawn alongside Spain in Group B.


LRMI Search
Search Google and then filter the results to see which sites use LRMI properties in schema.org markup.
This search is intended to help find sites using schema.org / LRMI, rather than use LRMI to help find resources.
- Search for a common word (e.g. 'the') and then use the filters to find pages that contain that word and one or any of the LRMI terms in schema.org.
- Can be used with a tool such as the OpenLink Structured Data Sniffer (OSDS) to show how the LRMI properties are being used the pages at urls returned.
Notes
The search is brittle in a number of ways, notably the number of results is over-reported. Separate to this some of the results returned do not currently contain the LRMI you might think it does.
Searches for properties in microdata and RDFa only, will not find LRMI being used in JSON-LD.
- A Google Customized Search Engine by Phil Barker.
Last modified: Feb 2020.
- Config files on github
- No copies of any of the resources searched are stored on or provided via PJJK servers in order to creat this page--it's all done by Google.


Toggle navigation
PETstagram
pets
Main
(current)
Profile
face
Drop
Action
Another action
Something
exit_to_app


Twitch TV API
Below are the channels for our App.
All
Online
Offline
Search:
{{chanel.channel}}
{{chanel.details}}
{{chanel.channel}}
{{chanel.details}}
{{chanel.channel}}
{{chanel.details}}


--- layout: default title: ReliefWeb River List, Thumbnails & Disasters include_rw: true ---
List view for reports, jobs and training in the river. Thumbnail view for Maps & Infographics
Sass files: modules/features/reliefweb_rivers/sass/_river-item.scss
Refugees, trafficking in persons and other effects of current conflicts would be a thematic focus of the Security Council in November, Sebastiano Cardi (Italy), Council President for the month, said at a press briefing today at Headquarters.
Refugees, trafficking in persons and other effects of current conflicts would be a thematic focus of the Security Council in November, Sebastiano Cardi (Italy), Council President for the month, said at a press briefing today at Headquarters.
Refugees, trafficking in persons and other effects of current conflicts would be a thematic focus of the Security Council in November, Sebastiano Cardi (Italy), Council President for the month, said at a press briefing today at Headquarters.


createor name
t-shirt name
In by an appetite no humoured return informed. Possession so comparison inquietufr
Size:
Colors:
Quantity:
Tags:
Footwear, Leather, Low, Sneakers, Suede
createor name
In by an appetite no humoured return informed. Possession so comparison inquietufr
Size:
Colors:
Quantity:
Tags:
Footwear, Leather, Low, Sneakers, Suede


The Men of Sigma Chi Omega, all have two major goals in mind; to better the Greek life at the University of Massachusetts from within, and to live our lives by the very principles established by the Seven Founding Fathers of Sigma Chi. Our interests in athletics, academics, business, science, engineering, and more will create a chapter with extraordinary talents; the range of individual interests is beneficial in creating a fraternity that will prosper with diversity in planning. The current members of the Sigma Chi Omega colony show passion in their pursuits We have members in many different majors, including the health sciences, business, and engineering. Our members are also active members in the UMass community, participating in many clubs and organizations such as ROTC. The diversity of our fraternity will only grow and continue to expand as we do in the Greek community.


Note: Your submissions won't be
visible on leaderboard for Public Challenge Phases
since you are a challenge host
for this challenge.
This feature is only for your testing purposes.
$ pip install evalai{{challenge.cliVersion}}
$ evalai set_token {{challenge.authToken}}
$ evalai push <image>:<tag> --phase <phase_name>
Team name: {{challenge.phaseRemainingSubmissions.participant_team}}
| Phase details | Remaining submissions | Submission command | ||
|---|---|---|---|---|
| {{key.name}}
Start date: {{key.start_date | date:'medium'}} End date: {{key.end_date | date:'medium'}} |
Today:
{{key.limits.remaining_submissions_today_count}} This month: {{key.limits.remaining_submissions_this_month_count}} Total: {{key.limits.remaining_submissions_count}} |
{{key.limits.message}} Next submission will be available in
{{challenge.phaseRemainingSubmissionsCountdown[key.id].days}}
Days, {{challenge.phaseRemainingSubmissionsCountdown[key.id].hours}}
hours : {{challenge.phaseRemainingSubmissionsCountdown[key.id].minutes}} minutes
:
{{challenge.phaseRemainingSubmissionsCountdown[key.id].seconds}} seconds
|
{{key.limits.message}} {{key.limits.maxExceededMessage}} |
$ evalai push <image>:<tag> --phase {{key.slug}}
|
Sorry, the challenge is not active.


Start your App Development with the Slateblue Mobile kit. it's fully coded for mobile app development, based on Angular and Bootstrap.


Hello! :) This is my portfolio.
This portfolio highlights the projects I have been involved in during my Computer Science journey. Enjoy!
But first:
This is a random feature that gives a Thanos quote when clicked:
Listed below are the projects I have been involed in:
This project involves developing data acquisition and organization tools for Dr. Zoe Boekelheide's condensed matter research laboratory in Lafayette College. I was involved in developing central remote control programs for all devices and recording instruments in the lab, creating data piplelines to feed into analytic programs and creating GUIs to help send instructions using few buttons instead of interacting with computer code.
This is my first ever CS project and I am proud to still be working on it :)
This was my third project in Data Structures and Algorithms class in Fall 2019. It involved using graphs to simulate a rideshare network tracking data like:
This project involved using primary uses Djikstra's algoritm to calculate shortest path with a changing traffic network environment.
This was my first project in Data Structures and Algorithms class in Fall 2019. It involved using linked lists and queues to simulate the operation of an eatery on Lafayette College giving data such as:
This project involved creating a graphical representation of mazes used in the IEEE Micromouse competition . This makes it easy for engineers to focus on developing and improving their mice while this tool creates random maps instantly when necessary for testing.
This random maze generator is built in such a way that every cell is accessible from any other cell which is not exactly a requirement for IEEE Micromouse competition. This creates a chance for the mice to truly find the shortest path out of the maximum number of possibilities.
This is the second project for my Data Structures and Algorithms class of Fall 2019. This involved creating a game simulation with the user as the manager of a mine with workers with different abilities on a rectangular map digging for gold while trying to avoid hazards like lava, pits/sinkholes and underground rivers.
Thanks for visiting :). Sena Yevenyo-2020


To become a Gladiator your level must be over 40 and you must collect the Mark of the Challenger, the Mark of Trust, and the Mark of the Duelist.
I see that you have all the marks but your skill level is still insufficient. Come back after more training and I shall change your occupation to Gladiator.


I did not participate in Tobiis IPO it did however happen the same week as I got a godson whose name is Tobias. In August 2015 it was time for his baptism I figured it would be a nice gift to start a small portfolio for him. I wanted to invest in a smaller tech company that had potential to do cool stuff over the next 20 years. It would be optimal if it would be in products that he will use when he is 12 so he can brag for his friends about being an owner.
The similarity between his name and Tobii and the proximity in time between their IPO and his birth draw my focus to Tobii. So I started reading a little bit about them. I liked the fact that they had two branches (Tobii Dynavox and Tobii Pro) that was actually making money, even if the money they made did not cover all of their investments in Tobii Tech it felt I took it as a verification that their technology was good enough to get custommers. And with the existance of Tobii Tech which had nice potential it seemed to fit most of the criteria I had set up.
So I bought a few shares for my godson and figured I had to put my money where my mouth was so I bought a little bit for myself as well. I made my entry around 50 SEK and the first thing that happens is that it falls almost 20%. I think I had lost 10% of the gift before the baptism... That did not feel great but on the other hand the investment horizon was 20 years not 4 days.
You can view the year that has been since I made the investment from two perspectives. What has happened to the stock and what has happened in the company.
Looking at the stock price it would seem that the last year has been quite dramatic. A fast rice up to 80 SEK then falling back towards 60 before sky rocketing to 87 just to collapse back down again before starting a more stable incline. It has been intresting to follow but a little bit puzzling due to my view on what has happened in the company.
As far as I can tell not much unexpected stuff happened in the period August 2015 - August 2016. The company delivered the same type of quarterly reports as before: Earning a little bit of money from Dynavox and Pro and investing a lot in Tech. This was exactly what I was expecting and hoping for but to my mind no reason for the stock price to go bananas.
With the start of september however the company released some exciting news. Orders from Acer and Dell regarding integrated eye tracking in highend gameing computers. Even if the amounts that Tobii will be able to invoice based on these orders won't be astronomical I think it marks a starting point.
It seems to me that Tobii Tech hopefully will be able to pull its own weight.
I think there are similarities between computers and cars in some ways. I think what is custom features in highend products will soon be standard in high end and custom in the mid range, and then it trickles down and becomes standard all over the place. At least if the feature brings something to the table.
This is what I hope will happen with eye tracking in computer screens. I think that cool and nifty things can be achieved be developers all over the world if they had a nice eye tracking api built in to computers.
The evaluation if Tobii is quite high at and they need to make a lot of money to fill those shoes but I think they are positioned nicely and there is always the possibility of someone with a little bit of cash buying them.


Level of Difficulty
Beginner
Intermediate
Advanced
Price Range
$26-$100
Course Duration
Days
Keywords
HTML
Beginner
Table
REFRESH
{% for elem in resultslist%}
{{ elem.company }}
{{ elem.courseName }}
{{elem.description}}
{{elem.keywords}}
{%endfor%}


SAML to STS Extension
Extension Activated
Account Id
Profile Name
STS Session Expires
Extension settings


Before Change
By default, runs twice to shake out errors related to noops.
with temporary_dir(root_dir=self.workdir_root()) as workdir:
for i in xrange(0, iterations):
pants_run = self.run_test_compile(workdir, target, strategy, clean_all=(i == 0), extra_args=extra_args)
if expect_failure:
self.assert_failure(pants_run)
else:
self.assert_success(pants_run)
if expected_files:
to_find = set(expected_files)
found = defaultdict(set)
for root, _, files in os.walk(workdir):
for file in files:
if file in to_find:
found[file].add(os.path.join(root, file))
to_find.difference_update(found)
if not expect_failure:
self.assertEqual(set(), to_find,
"Failed to find the following compiled files: {}".format(to_find))
yield found
def run_test_compile(self, workdir, target, strategy, clean_all=False, extra_args=None):
args = [
"compile",
"--compile-apt-strategy={}".format(strategy),
After Change
By default, runs twice to shake out errors related to noops.
with temporary_dir(root_dir=self.workdir_root()) as workdir:
with temporary_dir(root_dir=self.workdir_root()) as cachedir:
for i in xrange(0, iterations):
pants_run = self.run_test_compile(workdir, cachedir, target,
strategy, clean_all=(i == 0),
extra_args=extra_args)
if expect_failure:
self.assert_failure(pants_run)
else:
self.assert_success(pants_run)
found = defaultdict(set)
if expected_files:
to_find = set(expected_files)
for root, _, files in os.walk(workdir):
for file in files:
if file in to_find:
found[file].add(os.path.join(root, file))
to_find.difference_update(found)
if not expect_failure:
self.assertEqual(set(), to_find,
"Failed to find the following compiled files: {}".format(to_find))
yield found
def run_test_compile(self, workdir, cachedir, target, strategy, clean_all=False, extra_args=None):


[Originally posted on Friday 24 July]
Boffins are at work mucking about with the Hooting Yard website to ensure its continued gorgeousness for years to come. While they go poking and prodding around in its innards, you may note some hiccups. Fear not. As Julian of Norwich said, “all will be well, and all will be well, and every manner of thing will be well”. Very sensible woman, that Julian. Had a pet cat.


--- layout: page body_class: "page_template" ---
Relativity Transit is written by Roger Ogden.
Relativity Transit is produced with the following hardware and software:
Camera
Computer and Peripherals
Software
Relativity Transit was created with the wonderful Jekyll and is currently hosted on Github Pages.
The site features a modified version of the Roon theme by Minh Nguyen.
Email<EMAIL_ADDRESS>Twitter: @_rogerogden
I love discovering and reviewing well-made products. If you have a product you’d like me to review here on Relativity Transit, please shoot me an email.
Relativity Transit uses affiliate links wherever possible. By using the links to products on Relativity Transit, you’re providing me with a small kickback. This helps me continue to write, and I’m incredibly grateful for that.


#include <math_ops.h>
Counts the number of occurrences of each value in an integer array.
Outputs a vector with length size
and the same dtype as weights
. If weights
are empty, then index i
stores the number of times the value i
is counted in arr
. If weights
are non-empty, then index i
stores the sum of the value in weights
at each index where the corresponding value in arr
is i
.
Values in arr
outside of the range [0, size) are ignored.
Arguments:
Tensor
.Tensor
.Tensor
with the same shape as arr
, or a length-0 Tensor
, in which case it acts as all weights equal to 1.Returns:
Output
: 1D Tensor
with length equal to size
. The counts or summed weights for each value in the range [0, size).
Constructors and Destructors |
|
|---|---|
Bincount(const ::tensorflow::Scope & scope, ::tensorflow::Input arr, ::tensorflow::Input size, ::tensorflow::Input weights)
|
Public attributes |
|
|---|---|
bins
|
|
operation
|
Public functions |
|
|---|---|
node() const
|
::tensorflow::Node *
|
operator::tensorflow::Input() const
|
|
operator::tensorflow::Output() const
|
|
::tensorflow::Output bins
Operation operation
Bincount( const ::tensorflow::Scope & scope, ::tensorflow::Input arr, ::tensorflow::Input size, ::tensorflow::Input weights )
::tensorflow::Node * node() const
operator::tensorflow::Input() const
operator::tensorflow::Output() const


This page should be replaced with default landing page before the user logs in.
Non authenticated users don't have access to survey


Lorem Ipsum
Lorem
Reschedule your Batch/Class at Your Convenience
learn from your experts and get Real-Time Guidance


Last updated July 13, 2019
RentJO Cars is committed to respecting and safeguarding your privacy and personal information details in accordance to the data protection laws and thus takes great care to ensure the protection of any personal or non personal data collected from you. Following and adhering to UK and European data protection laws, we do our best to protect, secure and control misuse of your personal information shared with RentJOCars.com. Using right protocols and security measures, we use the stored information only for customised, enhanced and better service, to market, for adverts purpose, to get customer feedback on service and to communicate for completing bookings or updating on modifications. Read the following privacy policy carefully to understand the basis on which the personal data collected is used, by us at this website.
When you make bookings with us, you need to provide us with basic details including your full name, residential address, your contact number as well as credit/debit type along with its expiry date. To process the booking, we also require you to provide the driver's age. As a car hire booking agent, RentJOCars.com passes your given booking details and information to our car rental suppliers to verify your rental booking.
In order to serve you with better service, RentJOCars.com website makes limited use of cookies. However, we make sure we don't store any of your credit card or personal information in these cookies. These cookies store basic information to help us provide better and more enhanced as well as user friendly services or website experiences.
While some cookies are deleted automatically as you end the browsing session, there are others that need to be deleted by you by changing the settings.
Cookies are stored to help a website analyse the useful data to customise and enhance the user’s experience at the website. Pages visited, ads clicked, time spent on a page or product, language option selected, currency preferred etc are what helps a website in providing a better service.
We make use of site tracking software to keep a check on visitors coming to our site as well as to improve design and content of our site. This software uses a cookie system to capture and measure such details as site usage patterns and page views. Cookies are text files sent to your browser and stored on your computer's hard drive. In order to receive or block cookies, you can set your browser settings accordingly.
You can always activate or deactivate the cookies or cookie setting to stop storage of the cookie data.
All the personal information collected by RentJOCars.com while you create a booking with is secured and used wisely for specific reasons like - To complete & monitor the bookings and to coordinate with the supplier. To get in touch with you for a review or feedback on the service provided. To provide a better support by helping you make changes in the booking, getting back to your support related requests etc. To market the latest offers, deals or price drop or any new launches in terms of new product etc. To inform on booking status like unavailability of certain car or failure of a payment or upgrade to new offer or car. To analyse our services, coordination of support team with you and the issues if any on the website or in communication system.
RentJOCars.com is committed to make sure that the details provided in making a booking is kept secure. We make use of Secure Socket Layer or SSL technology as a standard process, to secure the information. This technology encrypts all the personal details including your credit card information given by you, in such a way that it cannot be misused or read as it's passed on internet. After the completion of the transaction, your given information is secured on the computer and not server, to ensure that it's safe and cannot be accessed via Internet.
We do not store any Credit card details on our website and nor do we share any payment transactions details. All payments are secured.
You can also subscribe to special offers and services to receive emails from us informing you of new services or promotions, offered by us. You can choose to unsubscribe this service anytime you wish by simply clicking on the unsubscribe link, given in the emails received by you. By using services of a data mailing provider, we facilitate dispatch of such promotional updates and e-mails to you. We make sure that the provider maintains the confidentiality of your personal information confidential all the times.
To subscribe or unsubscribe to Newsletters and other promotional emails click here.
For training and purpose of improving our services, we track and record phone calls made to us.
RentJOCars.com does not reveal it's your personal information to any third party without any prior consent from you, except in emergency situations or if or when we are lawfully obliged to do. We do not sell or hire any personally identifiable details received by us from you.
RentJOCars.com might supply statistics about you, sales along with booking patterns as well as third party related information, but it will not enclose any personal information.
Certain details would be shared with third companies like the suppliers or rental companies offering you the car to help complete the booking, maintain communication and keep you updated on any rental car service change or upgrade. This include but is not limited to name, person's age, contact number and address, residential place info like place of birth, DL details, payment type preference etc.
By making use of this web site you assent to the compilation, storage as well as utilisation of this information by RentJOCars.com as specified in our privacy policy. In case of any change in our privacy policy, the changes get posted on the page of privacy policy to keep you informed about information collected and used by us and under what circumstances.
If you have questions, comments or complaints about this Privacy Policy or our privacy practices, or would like to exercise any of your rights and choices under this Privacy Policy or applicable law, you may contact our Data Protection Officer at the following email address<EMAIL_ADDRESS>We may occasionally update this Privacy Policy. When we do, we will also revise the "updated date" on the Privacy Policy. For changes to this Privacy Policy that may be materially less restrictive on our use or disclosure of personal information that you have provided to us, the new policy will not apply to information collected prior to the change unless we obtain your consent. We encourage you to periodically review this Privacy Policy to stay informed about how we are protecting the personal information we collect. Your continued use of the Service constitutes your going forward agreement to this Privacy Policy and any updates.
This privacy policy was last updated on July 13, 2019..


Quick facts
- Name
- Impulse PL
- Birth Date
- September 1, 2015
- Place of birth
- Kathmandu, Nepal
- Conception
-
Who we are
About us
We are individuals united with common goal of providing promt, effective and efficient solutions to the clients. Moreover, we want to utilize our acedemic excellence and experience to provide excellent services.
What we offer
We foucs on providing continuos support and maintenace services to our clients.
Our staff
We have diverse staff specializing at various fields of the latest technology.


We are a team of researchers at the University of Virginia exploring new ways to bring advancements in computing and data science to society’s most challenging water resources management problems.
We are members of the interdisciplinary Link Lab, a 17,000 square foot laboratory in the Engineering School at the University of Virginia that brings together faculty and students with a shared interest in cyber-physical systems. If you are interested in joining our team, please check out our openings.
In addition to the publications, general research interests, and example projects on this site, we also maintain a Github organization where much of the the code resulting from our research is released free and open source.


Resume
Objective
To obtain an internship in CS or SE for summer
Education
CS in Rose-Hulman Institute of Technology gpa:0
- RHIT, terre-haute, IN
- major in CS, minor Math
- haven't study abroad
Related Courses :
- CSSE220
- MA276
- MA381
Applicable Project Work :
- Reading group on novel "holes"
- Group project on arcade game
Skills :
- Programming Languages :
- JAVA,C#,SQL
- Web-based Languages :
- XML,HTML,CSS,JS
- Softwares :
- Eclipse,Visual Studio Code
Selected Experience
-
Mock United Nations
Winter 2018-Summer 2020
Different experiences on different positions
Beijing, China
- Stay in different positions and lead the team to gain maximum profits at last
-
Mock United Nations
Winter 2018-Summer 2020
Different experiences on different positions
Beijing, China
- Stay in different positions and lead the team to gain maximum profits at last
-
Mock United Nations
Winter 2018-Summer 2020
Different experiences on different positions
Beijing, China
- Stay in different positions and lead the team to gain maximum profits at last
-
Mock United Nations
Winter 2018-Summer 2020
Different experiences on different positions
Beijing, China
- Stay in different positions and lead the team to gain maximum profits at last
-
Mock United Nations
Winter 2018-Summer 2020
Different experiences on different positions
Beijing, China
- Stay in different positions and lead the team to gain maximum profits at last
Activities & Honors
- Honar1
- Honar2
- Honar3
- Honar4
- Honar5


?6
7
8
9
10
.
.
.
.
The
New
York
Copyright
reserved
Botanical
Garden
y
|r^n
£
L
4
H
0
**»
•
*v
e/t0.
in
1910
Coll.
H.
von
Tiirckheim.
§8|ste
//IJis-tsikf?'
jl
"jAj>
CTC4--A~*A^
£cr-f.-tA*Q
J{*4C4..
_
FLORA
VON
SANTO
DOMINGO.
01334609
Legend -
Level of confidence that token is an accurately-transcribed word
extremely low
very low
low
undetermined
medium
high
very high


?username?
?required
?name?
required
?password?
?required?
confirmPassword
Not same as confirmPassword
?confirm?
?required?
password
?Not same as password?
?save?


Async Unicorns love Rust
July 26, 2020
Before going on to write a backend for our weather station we first need to familiarize ourselves with a few concepts from the Rust world. If you are unfamiliar with the language take a few minutes to read through Learn Rust in Y minutes to get used to the syntax.
When we will write a Telegram bot with Rust, we will use a technique called asynchronous programming. Let’s tackle what that means.
Table of Contents
- Build yourself a weather station. Part I
- Building yourself a weather station. Part 2
- → Async Unicorns love Rust
- Building a Weather Station Bot
- Building a Weather Station UI
Selling unicorns. Synchronously
Our bot will use a paradigm called asynchronous input-output, so we will need to understand what is standing behind those words. To understand this, let’s first define what we mean by synchronous input/output.
Imagine we need to get the contents of a web page into our program. For example, let’s suppose that we want to write an app that allows users to buy unicorns using a command-line interface 🦄. Turns out that there are a lot of techies in the unicorn-lover community 👨🏻💻, so the investors bought in and agreed to finance the project.
We have partnered with one of the best online shops who has given us an address of the best deals page: http://unizon.com/best-deals
. So, we need to fetch the data from this page. The most straightforward way to do this would be to find some HTTP client library that implements low-level details of fetching the web page via HTTP protocol:
// Initialize our HTTP client library.
// The one we use here does not really exist,
// so consider the code below as pseudocode
let client = Client::new();
// Get the response
let resp = client.get("[http://unizon.com/best-deals](http://unizon.com/best-deals)");
println!("Response: {}", resp.body());
Under the hood this code does the following:
Here, client.get
is a blocking call. This means that our main application Buy'a'Unicorn App
needs to wait while lower-level components fetch the request.
This overhead may be acceptable, but imagine that we will start making thousands of requests. Then, most of the runtime our app will wait while numbers are running back and forth over the wires.
Now, suppose that our userbase has grown and we have decided that we need to get more partners on board. We have found a few dozen of other shops that joyfully agreed to join our platform. The functionality of our app has expanded: we now have price lists, filters, sortings, and many other exciting command-line options. This means more work inside the main app, and more requests to other 🦄 shops.
We realize that our app does not scale anymore. The more new shops we add, the more we will need to wait for network I/O. This means we need to escape the bottleneck if we want our little unicorn business to grow.
Tangling Threads
One way to do this would be to introduce threads. Threads are lightweight (but not free) concurrency primitives that allow you to execute parts of your appreciation in a non-blocking manner. This means that we can use them to issue multiple HTTP requests to unicorn shops in parallel and automatically update data as it is coming in.
Before continuing, let’s first tackle what stands behind parallelism and concurrency to make things more clear. CPU at your computer har multiple mini-CPUs inside called cores. Those cores allow executing multiple low-level instructions in parallel. Multi-core execution on a 4-core CPU will allow us to execute 4 tasks independently of each other. But let’s see how many parallel processes my laptop can handle:
$ ps aux | wc -l
875
That’s a lot more than 4, right? How is this possible? If you use Intel CPUs, then most of them will have a hyper-threading option available, which will separate each physical CPU core into two logical cores which can be used by your operating system.
Doubling the core number is still not sufficient to run 875 processes, so there is more to it than hyperthreading. It turns out that most of the time applications you run wait for something: user input, hard drive, network communication. Operating systems leverage this fact to fake parallelization by introducing a thing called concurrent execution.
Two processes are executing concurrently if they can execute in overlapping periods of time. However, it does not mean that they execute their instructions at the same time. For example, one concurrent process can pause and let the other run. And when two processes execute their instructions simultaneously they are called to be run in parallel.
Operating systems provide complicated schedulers that automatically control which processes execute in parallel, which concurrently and how exactly they should switch between each other. In practice, concurrent execution happens so fast that for us it looks like all of the processes are running in parallel.
Next, let’s clarify the difference between two related concepts: processes and threads.
The process represents an executing program in an operating system. Each process is completely isolated from other processes. The only way one process can communicate to another is by utilizing some external shared resources. For example, a file system, or a database server. Due to their properties, processes have some overhead. Creating and maintaining processes takes time, and switching between them requires work too.
Let’s look at how we can use processes in Rust:
use std::process::Command;
// execute echo command and save it's output to the variable
let output = Command::new("echo")
.arg("Hello world")
.output()
.expect("Failed to execute command");
assert_eq!(b"Hello world\n", output.stdout.as_slice());
// in this way, we could fetch data using external applications
let response = Command::new("curl")
.arg("http://unicorn.shop/store/items")
.output()
.expect("Failed to execute command");
If our unicorn shop app needs to communicate with tens or hundreds of different shops, then processes might solve our issue. However, if we will scale to thousands of shops (for which I have absolutely no doubt), then processes will start to feel show and sluggish.
The more lightweight concept of threads comes to our rescue. Think of them as a set of lightweight mini-processes inside your large process. Threads are much faster to create and destroy. Also, they share memory access, so you won’t need to use expensive I/O-based communication protocols just to share information inside your own application. However, all this power comes with a grain of salt.
Shared memory access complicates the programmer’s job by a lot. It introduces notoriously hard to debug problems such as data races and deadlocks. Thankfully, Rust takes away most of that pain. The borrow checker introduces strict mutability control that allows the Rust compiler to ensure that two different threads do not share simultaneous access to a single variable. Of course, there are ways to circumvent this, but it takes a lot of conscious effort to break through Rust’s safety net. Let’s see how we can manipulate threads in Rust:
use std::thread;
use std::sync::mpsc::channel;
// MPSC stands for Multiple Producer Single consumer.
// Channels are a useful abstraction for communication between threads:
// tx (transmitter) allows multiple producers to send data over the channel,
// rx (receiver) allows a single consumer to recieve the data from producers.
// In our case, tx will be used by multiple threads to send responses to our reciever thread
let (tx, rx) = channel();
let sender = thread::spawn(move || {
// We will use an imaginary API for sending HTTP GET requests for simplification
let response = get_http_response(String::from("http://unicorn.shop/store/items"))
tx.send(response)
.expect("Unable to send on channel");
});
let receiver = thread::spawn(move || {
let value = rx.recv().expect("Unable to receive from channel");
println!("{}", value);
});
sender.join().expect("The sender thread has panicked");
receiver.join().expect("The receiver thread has panicked");
Creating a thread each time we need to perform can still be costly, so we can introduce another useful tool: a thread pool. Thread pool herds a number of threads and gives you a free one each time you need it:
// Rust standard library does not provide a thread pool implementation,
// so we will a `threadpool` crate.
// https://docs.rs/threadpool/1.8.1/threadpool/
use threadpool::ThreadPool;
use std::sync::mpsc::channel;
// Create a thread pool with 4 worker threads ready to handle our requests
let n_workers = 4;
let pool = ThreadPool::new(n_workers);
// Our shop URLs
let shops = vec![String::from("http://unicorn.shop/store/items"),
String::from("http://all-unicorns.ml/inventory")];
// Issue each request in a thread pool.
// The for loop won't block on `pool.execute` call
let (tx, rx) = channel();
for shop_url in shops.iter() {
let tx = tx.clone();
pool.execute(move|| {
// Again, using our fictionary API to send requests to
// imaginary unicorn shops :)
let response = get_http_response(shop_url)
tx.send(response).expect("channel will be there waiting for the pool");
});
}
// We can do other stuff without waiting for responses
some_important_work_to_do();
// Here, the loop will print request in the order
// they arrive from the shop servers
while let Some(response) = rx.iter() {
println!("{}", response);
}
Now that you know how to use threads, let’s fast-forward our unicorn business for a few years. We are still growing, and now almost all shops are integrated into our platform. Someday, unicorn appliances and care products sellers got interested in providing co-sell options so that you won’t only buy a unicorn, but a fully packed experience with the best saddle and latest horn care shampoo on the market.
All this means that we will have a great expansion of our service, and a lot more HTTP requests to do. Also, our application starts to become more complex. New additions to the business logic introduce lots of buds and are slower to implement. The threading backend that we use won’t keep up with the job anymore.
Async to the rescue
To solve our problems, we must shift the paradigm. Up to this point, we thought about our application in two parts: the main thread that handles all of the application logic and several worker threads in a thread pool that handles networking I/O for us.
But why do we need to switch threads in the first place? Why code in our main thread can’t continue executing while some other part of the application is waiting for an I/O? In fact, every major operating system provides an API to handle off the I/O work to the OS kernel and receive notifications when data is available for reading.
This functionality can be leveraged to avoid blocking on the I/O code in a single thread: if your application encounters an I/O call it can continue executing other tasks while waiting for the data to become available In Linux, this functionality is available via epoll
API . In reality, this turns out to be a fairly complex task that can be implemented with the event loop architecture pattern.
As you can see, the event loop operates by observing events and executing tasks. A task can be thought of as an abstraction over a block of code. The event loop works by observing I/O events from the operating system and executing tasks that read or write data.
This model introduces a significant drawback compared to the traditional approach: the event loop runs in a single thread. This means that if our tasks contain anything but I/O operations their execution will block the entire event loop. That leads to a conclusion: if your application uses a lot of I/O requests, it will get a big performance boost from using the event loop approach. However, if it is CPU-heavy and uses lots of computational resources, it will block the event loop too much for it to provide any benefit. Modern asynchronous libraries provide a way to fight this by providing an additional thread pool which can be used to execute blocking tasks without stopping the event loop.
Another important part of the solution is the asynchronous programming paradigm. Modern programming languages simplify working with asynchronous code by providing special syntax constructs. For example, Rust allows us to define async
closures and functions.
// `block_on` blocks the current thread until the provided future has run to
// completion. Other executors provide more complex behavior, like scheduling
// multiple futures onto the same thread.
use futures::executor::block_on;
async fn hello_world() {
println!("hello, world!");
}
fn main() {
let future = hello_world(); // Nothing is printed
block_on(future); // `future` is run and "hello, world!" is printed
}
The above example is from from the Asynchronous Programming In Rust. I suggest reading the book for a more in-depth intro into async Rust.
Each asynchronous function returns a Future
, a special construct that designates a result, which will be returned sometime in the future. Notice that the hello_world
function will not be executed until we block_on
the future.
In practice, we will work with a tokio crate, which implements the event loop pattern and wraps the mio
library that uses the underlying operating system’s asynchronous I/O implementation and wraps it in a convenient interface. Another important library we will use in the ESP weather station project is tbot, a Telegram bot library built on top of tokio
. Let’s look at how to build a simple bot with it:
use tbot::prelude::*;
use tokio::sync::Mutex;
#[tokio::main]
async fn main() {
// We create the bot's event loop by using token from the environment variable BOT_TOKEN
let mut bot = tbot::from_env!("BOT_TOKEN")
.event_loop();
// next, we register a command which greets the user with a predefinend message
bot.command("say_hi", |context| {
// this construct allows us to move variables from the enclosing environment into
// the closure below
async move {
let message = String::from("Hi there!");
// finally, we issue a blocking call that sends the message back to the user.
// await.unwrap() allows us to force the execution of a send_message API call.
// without it, nothing would happen
context
.send_message(&message)
.call()
.await
.unwrap();
}
});
// here, we start the Telegram API poller which will periodically ask the server about new events
// such as incoming messages
bot.polling().start().await.unwrap();
}
Notice the #[tokio::main]
macro. According to the documentation, it “marks async function to be executed by selected runtime”. By runtime we mean the underlying implementation of tokio’s scheduler that executes tasks. As defined in the framework’s documentation, the runtime consists of the following components:
- An I/O event loop, called the driver, which drives I/O resources and dispatches I/O events to tasks that depend on them.
- A scheduler to execute tasks that use these I/O resources.
- A timer for scheduling work to run after a set period of time.
Wrapping up
Now, we can scale our small unicorn shop to be a global bot-powered marketplace where buyers and sellers can satisfy their unicorn needs 24/7, worldwide by using an asynchronous programming model. Apart from that, that’s all we needed to cover to start developing a chat bot for our weather station.
We have looked at three ways of dealing with I/O in our application:
- Synchronous I/O, where everything happens in the same thread
- Threaded I/O, where we offload I/O work to a different thread by paying the cost of creating threads and switching between them
- Asynchronous I/O, where we use the event loop pattern to offload the I/O work to the operating system and receive notifications via special APIs such as Linux
epoll
when our I/O requests are done
While providing extremely fast I/O, the asynchronous paradigm is not without its drawbacks:
- It is harder to read, write and maintain async code
- Async I/O benefits diminish with the amount of CPU-heavy computations you need to make
In the next post, we will be looking at how to build a Telegram bot for our weather station using Rust as a programming language, Tokio as an async I/O library and tbot as a Telegram bot framework.


Arrays and Hashes
Arrays and hashes are very similar, but also have very distinct uses. In Ruby, everything is an object, and arrays and hashes are collections of objects.
In an array, each item contained can be almost any kind of object, like strings, numbers, or even other arrays.
Here's some examples of arrays...
array1 = [1,5,4,2,80] array2 = ['clown', 'box','tar','cat'] array3 = [56, 'pencil', ['work', 41, 'gauntlet'], '99']
Each item in an array's position is marked in order by an index number (starting with zero), like array_name[indexNumber].
For example,
array3[0] = 56 array3[2] = ['work', 41, 'gauntlet'] array3[2][0] = 'work'
Hashes are very much like arrays, except that each entry contains a pair of items, a "key" and a "value". The key points to the value and each key within the same hash must be unique.
A hash looks like this
hash_name = { "age" => 58, "address" => "451 Yorkshire Ln.", "occupation" => "Bible salesman" }
The values in the hash can be accessed by using the keys.
hash["age"] = 58 hash["address"] = "451 Yorkshire Ln."
A hash can be useful in situations where one object has many different properties with values or to store values for many different objects.


{% extends "base.html" %} {% load staticfiles %} {% block titlesuffix %} - Request site{% endblock %} {% block head %} {{ block.super }} {% endblock %} {% block main %}
This form is only for the creation of club or activity websites.
Please fill out the form below if you want a website for your activity. You will be notified about the status of your request via email. You will need a teacher's approval if you need services for a class or club / group / organization that is recognized by the 8th period office and the TJHSST administration. This request will be valid until the end of the current school year. Service requests must be submitted before the last day of the school year for requested services to not expire. If you have any questions, please contact {{ DJANGO_SETTINGS.DIRECTOR_CONTACT_EMAIL }}.
All information about your request will be sent to this email address: {{ request.user.email }}
Please make sure you check it regularly.


GetAsCSSReturns text converted to the CSS (Cascading Style Sheets) format.CSS format is an internet text format similar to HTML. CSS supports more text formats than HTML, so CSS will represent what you have typed more accurately.Note The GetAsCSS function does not return formats that are set in the Conditional Formatting dialog box.GetAsCSS(text) returns the example result shown below when the field text contains the word “Frank” and the word Frank has the following text attributes: Font = Helvetica, Font Size = 12 points, Font Color = red, Font Style = bold.


WATCH: Alex Trebek nearly brought to tears by 'Jeopardy!' contestant's final answer
by Michelle Ewing, Cox Media Group National Content DeskTime to get out the tissues.
A "Jeopardy!" contestant's heartwarming tribute to Alex Trebek prompted an emotional response from the show's longtime host – and many viewers, as well.
According to USA Today and the Gainesville Times, the moment came during Monday night's Tournament of Champions episode as Brown University student Dhruv Gaur, of Gainesville, Georgia, revealed his Final Jeopardy response.
"You're smiling. I like that," Trebek, who is battling pancreatic cancer, told the grinning 18-year-old. "Let's take a look at your response. Did you come up with the right one?"
But Gaur had not.
"What is, 'We love you, Alex,'" Trebek read from Gaur's blue screen. "That's very kind. Thank you."
The 79-year-old then paused and took a deep breath, appearing to hold back tears before unveiling Gaur's wager.
"Cost you $1,995," Trebek continued, still visibly emotional. "You're left with $5."
After the episode aired, Gaur, who finished behind the two other contestants, took to Twitter to explain his actions.
"For context, Alex had just shared with us that he was re-entering treatment for pancreatic cancer. We were all hurting for him so badly," Gaur wrote. "When Final Jeopardy came up, I could've tried to puzzle it together, but really, just kept thinking about Alex, and thought he should know."
He added: "I'm just very grateful I got the opportunity to say what I know everyone was thinking. Sending all the love."
Gaur tagged the post, "#weloveyoualex."
Fellow fans praised Gaur's move.
"Thank you for doing so," Twitter user @MizCoretta replied. "Yours will always be the correct answer. You're awesome."
"It was perfect," wrote @JenDurant3. "In my mind, you won final #Jeopardy."


Data Fields | |
| int | iEngineClock |
| Current engine clock in 10 KHz. | |
| int | iMemoryClock |
| Current memory clock in 10 KHz. | |
| int | iActivityPercent |
| int | iCurrentPerformanceLevel |
| Not used. Reserved for future use. | |
| int | iCurrentBusSpeed |
| Current PCI-E bus speed. | |
| int | iCurrentBusLanes |
| Current PCI-E bus # of lanes. | |
| int | iMaximumBusLanes |
| Maximum possible PCI-E bus # of lanes. | |
| int | iExtValue |
| Value for future extension. | |
| int | iExtMask |
| Mask for future extension. |
This structure is used to store information about current Overdrive 6 performance status.
Current GPU activity in percent. This indicates how "busy" the GPU is.
Not used. Reserved for future use.
Maximum possible PCI-E bus # of lanes.
Value for future extension.
Mask for future extension.


WooAdmin
any
pending
processing
on-hold
completed
cancelled
refunded
failed
Sale Reprot
Top Sale
#:--
products
public
history
--
--
--
pending
processing
on hold
completed
cancelled
refunded
failed
--
--
Edit
Trash


forkify
Example modified from here.
H1 Header
Paragraphs are separated by a blank line.
2nd paragraph. Italic, bold, and monospace
. Itemized lists
look like:
- this one
- that one
- the other one
Note that the actual text content starts at 4-columns in.
Block quotes are written like so.
They can span multiple paragraphs, if you like.
H2 Header
Here’s a numbered list:
- first item
- second item
- third item
Note again how the actual text starts at 4 columns in (4 characters from the left side). Here’s a code sample:
# Let me re-iterate ...
for i in 1 .. 10 { do-something(i) }
As you probably guessed, indented 4 spaces. By the way, instead of indenting the block, you can use delimited blocks, if you like:
define foobar() {
print "Welcome to flavor country!";
}
(which makes copying & pasting easier). You can optionally mark the
delimited block for Pandoc to syntax highlight it by specifying the languagae after the start of a block (e.g. ~~~cpp
) which would look like :
#include <iostream>
using namespace std;
int main()
{
cout << "Size of char: " << sizeof(char) << " byte" << endl;
cout << "Size of int: " << sizeof(int) << " bytes" << endl;
cout << "Size of float: " << sizeof(float) << " bytes" << endl;
cout << "Size of double: " << sizeof(double) << " bytes" << endl;
return 0;
}
An H3 header
Now a nested list:
-
First, get these ingredients:
- carrots
- celery
- lentils
-
Boil some water.

Notice again how text always lines up on 4-space indents (including that last line which continues item 3 above).
Here’s a footnote 1.
Tables can look like this:
| Header 1 | Header 2 | Header 3 |
|---|---|---|
| data1a | Data is longer than header | 1 |
| d1b | add a cell | |
| lorem | ipsum | 3 |
| empty outside cells | ||
| skip | 5 | |
| six | Morbi purus | 6 |
A horizontal rule follows.
Here’s a definition list:
- apples
- Good for making applesauce.
- oranges
- Citrus!
- tomatoes
- There’s no “e” in tomatoe.
Again, text is indented 4 spaces. (Put a blank line between each term and its definition to spread things out more.)
Here’s a “line block” (note how whitespace is honored):
| Line one |
| Line too |
| Line tree |
and images can be specified like so:
Inline math equation: $\omega = d\phi / dt$. Display math should get its own line like so:
\[I = \int \rho R^{2} dV\]-
Some footnote text. ↩


--- layout: page status: publish published: true title: C/C++ author: display_name: Tomas Restrepo login: tomasr email<EMAIL_ADDRESS>url: http://winterdom.com/ author_login: tomasr author_email<EMAIL_ADDRESS>author_url: http://winterdom.com/ wordpress_id: 1052 wordpress_url: http://winterdom.com/?page_id=1052 date: '2009-04-27 03:56:25 +0000' date_gmt: '2009-04-27 03:56:25 +0000' categories: - Uncategorized tags: [] comments: [] ---
Here are some articles about C/C++ stuff I've written. Although I try to be as exact as possible, be warned that I'm no language lawyer =)


Previous: Examples of Inheritance, Up: Inheritance
The :default-initargs class option is inherited. The set of defaulted initialization arguments for a class is the union of the sets of initialization arguments supplied in the :default-initargs class options of the class and its superclasses. When more than one default initial value form is supplied for a given initialization argument, the default initial value form that is used is the one supplied by the class that is most specific according to the class precedence list.
If a given :default-initargs class option specifies an initialization argument of the same name more than once, an error of type program-error is signaled.


I have learnt about various html tags such as html,head,title,body,h1,hr,img and p
This is my first website.


This work was packaged for Debian by:
Jeff Breidenbach on Mon, 28 Feb 2011 17:25:17 -0800
It was downloaded from
Upstream Author:
Pascal Massimino
Copyright:
Copyright (C) 2010, Google Inc. All rights reserved.
License:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Google nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.

The Debian packaging is:
Copyright (C) 2011 Jeff Breidenbach
and is licensed under Apache-2.0
see `/usr/share/common-licenses/Apache-2.0'.


:::tip What You’ll Learn
:::
:::info Prerequisites
:::
Welcome to the React Redux Quick Start tutorial! This tutorial will briefly introduce you to React Redux and teach you how to start using it correctly.
This page will focus on just how to set up a Redux application with Redux Toolkit and the main APIs you’ll use. For explanations of what Redux is, how it works, and full examples of how to use Redux Toolkit, see the Redux core docs tutorials.
For this tutorial, we assume that you’re using Redux Toolkit and React Redux together, as that is the standard Redux usage pattern. The examples are based on a typical Create-React-App folder structure where all the application code is in a src
, but the patterns can be adapted to whatever project or folder setup you’re using.
The Redux+JS template for Create-React-App comes with this same project setup already configured.
Add the Redux Toolkit and React Redux packages to your project:
Create a file named src/app/store.js
. Import the configureStore
API from Redux Toolkit. We’ll start by creating an empty Redux store, and exporting it:
```js title=“app/store.js” import { configureStore } from ‘@reduxjs/toolkit’
export default configureStore({ reducer: {}, }) ```
This creates a Redux store, and also automatically configure the Redux DevTools extension so that you can inspect the store while developing.
Once the store is created, we can make it available to our React components by putting a React Redux <Provider>
around our application in src/index.js
. Import the Redux store we just created, put a <Provider>
around your <App>
, and pass the store as a prop:
```js title=“index.js” import React from ‘react’ import ReactDOM from ‘react-dom’ import ‘./index.css’ import App from ‘./App’ // highlight-start import store from ‘./app/store’ import { Provider } from ‘react-redux’ // highlight-end
ReactDOM.render( // highlight-next-line
Add a new file named src/features/counter/counterSlice.js
. In that file, import the createSlice
API from Redux Toolkit.
Creating a slice requires a string name to identify the slice, an initial state value, and one or more reducer functions to define how the state can be updated. Once a slice is created, we can export the generated Redux action creators and the reducer function for the whole slice.
Redux requires that we write all state updates immutably, by making copies of data and updating the copies. However, Redux Toolkit’s createSlice
and createReducer
APIs use Immer inside to allow us to write “mutating” update logic that becomes correct immutable updates.
```js title=“features/counter/counterSlice.js” import { createSlice } from ‘@reduxjs/toolkit’
export const counterSlice = createSlice({ name: ‘counter’, initialState: { value: 0, }, reducers: { increment: (state) => { // Redux Toolkit allows us to write “mutating” logic in reducers. It // doesn’t actually mutate the state because it uses the Immer library, // which detects changes to a “draft state” and produces a brand new // immutable state based off those changes state.value += 1 }, decrement: (state) => { state.value -= 1 }, incrementByAmount: (state, action) => { state.value += action.payload }, }, })
// Action creators are generated for each case reducer function export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer ```
Next, we need to import the reducer function from the counter slice and add it to our store. By defining a field inside the reducers
parameter, we tell the store to use this slice reducer function to handle all updates to that state.
```js title=“app/store.js” import { configureStore } from ‘@reduxjs/toolkit’ // highlight-next-line import counterReducer from ‘../features/counter/counterSlice’
export default configureStore({ reducer: { // highlight-next-line counter: counterReducer, }, }) ```
Now we can use the React Redux hooks to let React components interact with the Redux store. We can read data from the store with useSelector
, and dispatch actions using useDispatch
. Create a src/features/counter/Counter.js
file with a <Counter>
component inside, then import that component into App.js
and render it inside of <App>
.
```jsx title=“features/counter/Counter.js” import React, { useState } from ‘react’ import { useSelector, useDispatch } from ‘react-redux’ import { decrement, increment } from ‘./counterSlice’ import styles from ‘./Counter.module.css’
export function Counter() { const count = useSelector((state) => state.counter.value) const dispatch = useDispatch()
return (

<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Increment
</button>
{count}
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Decrement
</button>

) } ```
Now, any time you click the “Increment” and "Decrement buttons:
<Counter>
component will see the new state value from the store and re-render itself with the new dataThat was a brief overview of how to set up and use Redux Toolkit with React. Recapping the details:
:::tip Summary
configureStore
configureStore
accepts a reducer
function as a named argumentconfigureStore
automatically sets up the store with good default settings<Provider>
component around your <App />
<Provider store={store}>
createSlice
createSlice
with a string name, an initial state, and named reducer functionsuseSelector/useDispatch
hooks in React components
useSelector
hookdispatch
function with the useDispatch
hook, and dispatch actions as needed:::
The counter example app shown here is also the
Here’s the complete counter application as a running CodeSandbox:
We recommend going through the “Redux Essentials” and “Redux Fundamentals” tutorials in the Redux core docs, which will give you a complete understanding of how Redux works, what Redux Toolkit and React Redux do, and how to use it correctly.


Search Map | Facility Level Search Expanded Map | Facility Level Search Result map | Pollutant Transfer Result map | Pollutant Transfer Expanded map | Pollutant Release Result map | Pollutant Release Expanded map | Facility Detail Map |
Are modules ready?Set map print detailsGet map extentSet map extentExclude layersExclude all layersinclude layers |
Query layersQuery layersQuery layers based on control in searchClear selectionLayer filtersLayer filter on all layersLayer filter one layerSet filter controlSet filter controlsGet control filtersRemove all filtersGet Visible LayersSet Visible Layers |


Bore Size: placeholder
Wet Weight: placeholder
Horse Power: placeholder
Bore Size: placeholder
Wet Weight: placeholder
Horse Power: placeholder
Bore Size: placeholder
Wet Weight: placeholder
Horse Power: placeholder
Bore Size: placeholder
Wet Weight: placeholder
Horse Power: placeholder
Bore Size: placeholder
Wet Weight: placeholder
Horse Power: placeholder
Bore Size: placeholder
Wet Weight: placeholder
Horse Power: placeholder


Rugby World Cup final: England prop Kyle Sinckler taken off with concussion
England prop Kyle Sinckler was taken off with concussion in the third minute of the Rugby World Cup final against South Africa.
The 26-year-old collided with team-mate Maro Itoje, trying to tackle Makazole Mapimpi, and immediately hit the floor.
There was a lengthy stoppage as Sinckler was assessed by the on-duty doctor, before he regained consciousness and walked off the field.
The Harlequins front-row was replaced by 32-year-old Dan Cole.
South African hooker Mbongeni Mbonambi was also taken off for a head injury assessment after being replaced by Malcolm Marx in the first half.
Analysis
Former England international and BBC Radio 5 Live pundit Paul Grayson
Sinckler's a runner, key to those pivot plays England use. Dan Cole is a good tight-head but not as nimble.
You think in an hour, with the pressure he'll be under, he's going to be drained.


FsiEvaluationSession
Namespace: FSharp.Compiler.Interactive
Parent Module: Shell
Represents an F# Interactive evaluation session.
Instance members
| Instance member | Description |
CurrentPartialAssemblySignature
Signature: FSharpAssemblySignature
|
Get a handle to the resolved view of the current signature of the incrementally generated assembly. CompiledName: |
DynamicAssembly
Signature: Assembly
|
Get a handle to the dynamicly generated assembly CompiledName: |
EvalExpression(code)
Signature: code:string -> FsiValue option
|
Execute the code as if it had been entered as one or more interactions, with an implicit termination at the end of the input. Stop on first error, discarding the rest of the input. Errors are sent to the output writer. Parsing is performed on the current thread, and execution is performed sycnhronously on the 'main' thread. Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered by input from 'stdin'. |
EvalExpressionNonThrowing(code)
Signature: code:string -> Choice<FsiValue option,exn> * FSharpErrorInfo []
|
Execute the code as if it had been entered as one or more interactions, with an implicit termination at the end of the input. Stop on first error, discarding the rest of the input. Errors and warnings are collected apart from any exception arising from execution which is returned via a Choice. Parsing is performed on the current thread, and execution is performed sycnhronously on the 'main' thread. Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered by input from 'stdin'. |
EvalInteraction(code)
Signature: code:string -> unit
|
Execute the code as if it had been entered as one or more interactions, with an implicit termination at the end of the input. Stop on first error, discarding the rest of the input. Errors are sent to the output writer, a 'true' return value indicates there were no errors overall. Execution is performed on the 'Run()' thread. Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered by input from 'stdin'. |
EvalInteractionNonThrowing(code)
Signature: code:string -> Choice<unit,exn> * FSharpErrorInfo []
|
Execute the code as if it had been entered as one or more interactions, with an implicit termination at the end of the input. Stop on first error, discarding the rest of the input. Errors and warnings are collected apart from any exception arising from execution which is returned via a Choice. Execution is performed on the 'Run()' thread. Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered by input from 'stdin'. |
EvalScript(filePath)
Signature: filePath:string -> unit
|
Execute the given script. Stop on first error, discarding the rest of the script. Errors are sent to the output writer, a 'true' return value indicates there were no errors overall. Execution is performed on the 'Run()' thread. Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered by input from 'stdin'. |
EvalScriptNonThrowing(filePath)
Signature: filePath:string -> Choice<unit,exn> * FSharpErrorInfo []
|
Execute the given script. Stop on first error, discarding the rest of the script. Errors and warnings are collected apart from any exception arising from execution which is returned via a Choice. Execution is performed on the 'Run()' thread. Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered by input from 'stdin'. |
FormatValue(...)
Signature: (reflectionValue:obj * reflectionType:Type) -> string
|
Format a value to a string using the current PrintDepth, PrintLength etc settings provided by the active fsi configuration object |
GetCompletions(longIdent)
Signature: longIdent:string -> seq<string>
|
A host calls this to get the completions for a long identifier, e.g. in the console Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered by input from 'stdin'. |
InteractiveChecker
Signature: FSharpChecker
|
The single, global interactive checker to use in conjunction with other operations on the FsiEvaluationSession. If you are using an FsiEvaluationSession in this process, you should only use this InteractiveChecker for additional checking operations. CompiledName: |
Interrupt()
Signature: unit -> unit
|
A host calls this to request an interrupt on the evaluation thread. |
IsGui
Signature: bool
|
A host calls this to determine if the --gui parameter is active CompiledName: |
LCID
Signature: int option
|
A host calls this to get the active language ID if provided by fsi-server-lcid CompiledName: |
ParseAndCheckInteraction(code)
Signature: code:string -> Async<FSharpParseFileResults * FSharpCheckFileResults * FSharpCheckProjectResults>
|
Typecheck the given script fragment in the type checking context implied by the current state of F# Interactive. The results can be used to access intellisense, perform resolutions, check brace matching and other information. Operations may be run concurrently with other requests to the InteractiveChecker. Due to a current limitation, it is not fully thread-safe to run this operation concurrently with evaluation triggered by input from 'stdin'. |
PartialAssemblySignatureUpdated
Signature: IEvent<unit>
|
Raised when an interaction is successfully typechecked and executed, resulting in an update to the type checking state. This event is triggered after parsing and checking, either via input from 'stdin', or via a call to EvalInteraction. CompiledName: |
ReportUnhandledException(exn)
Signature: exn:exn -> unit
|
A host calls this to report an unhandled exception in a standard way, e.g. an exception on the GUI thread gets printed to stderr |
Run()
Signature: unit -> unit
|
Load the dummy interaction, load the initial files, and, if interacting, start the background thread to read the standard input. Performs these steps: - Load the dummy interaction, if any - Set up exception handling, if any - Load the initial files, if any - Start the background thread to read the standard input, if any - Sit in the GUI event loop indefinitely, if needed |
Static members
| Static member | Description |
Create(...)
Signature: (fsiConfig:FsiEvaluationSessionHostConfig * argv:string [] * inReader:TextReader * outWriter:TextWriter * errorWriter:TextWriter * collectible:bool option * legacyReferenceResolver:Resolver option) -> FsiEvaluationSession
|
Create an FsiEvaluationSession, reading from the given text input, writing to the given text output and error writers. |
GetDefaultConfiguration()
Signature: unit -> FsiEvaluationSessionHostConfig
|
Get a configuration that uses a private inbuilt implementation of the 'fsi' object and does not implicitly reference FSharp.Compiler.Interactive.Settings.dll. |
GetDefaultConfiguration(fsiObj)
Signature: fsiObj:obj -> FsiEvaluationSessionHostConfig
|
Get a configuration that uses the 'fsi' object (normally from FSharp.Compiler.Interactive.Settings.dll, an object from another DLL with identical characteristics) to provide an implementation of the configuration. FSharp.Compiler.Interactive.Settings.dll is referenced by default. |
GetDefaultConfiguration(...)
Signature: (fsiObj:obj * useFsiAuxLib:bool) -> FsiEvaluationSessionHostConfig
|
Get a configuration that uses the 'fsi' object (normally from FSharp.Compiler.Interactive.Settings.dll, an object from another DLL with identical characteristics) to provide an implementation of the configuration. The flag indicates if FSharp.Compiler.Interactive.Settings.dll is referenced by default. |


Running and debugging Virgo instances from within the development environment is a handy feature for developers that will save them from switching back and forth across two different contexts (the IDE and the VIRGO server).
To set up this feature, first install the "Eclipse Virgo Tools" package from the repository: http://download.eclipse.org/virgo/milestone/IDE.
In order to do so, go to Help → Install New Software. There you can add the repository with the ADD button and you will find the packet once the repository is added.
To configure Virgo server inside eclipse goto Windows→Preference→Server option from the left panel and then choose runtime environment:
On the right side you may see an option to add servers, click "add" and type the server name "Virgo", then click "next" to type the server name, server installation directory and JRE:
Click "Ok" to finish, you will have your configured instance of Virgo Web Server in the list of available servers.
To add the server and the view console go to Windows→show view→servers. This will add the "server perspective" view, right click press new→server then filter for virgo and select the server already configured. You should see something similar to what you see in the next picture:
Finally, use the start and debug buttons (white "play" icon over green circle and bug icon respectively) to run the server in required mode and view the server console window for various logs. Note: You can drag a project and drop it directly on the virgo server entry in the "Servers" tab for direct deployment from within Eclipse (instead of dropping a jar inside the VIRGO_HOME\pickup directory which has a directory watcher thread scanning it for changes in its content).
Double click Virgo Server to view various attributes and properties as shown in the following image.
.


A while ago I wrote some thoughts on what SQLObject 0.6 might look like. Well, a lot of those things didn't happen (actually nearly all of them), though the plans were pretty speculative so it's no surprise it didn't happen. But I'm going through another set of refactoring for SQLObject 0.7 (and I'm already part way through it) so I can say better what will happen for that version.
SQLObject normally implements concrete table inheritance, mostly because that was the absolute minimum I could do so that it support any kind of inheritance at all. It was the best I could do to avoid the issue.
But some people like other kinds of inheritance. Daniel Savard implemented a patch to add another kind of inheritance, kind of like class table inheritance -- except that each row is actually typed as part of the most-parent-table.
Oleg Broytmann took over the patch, and after refactoring it a bit it's now part of SQLObject. You have to subclass from InheritableSQLObject to actually use this kind of inheritance (I still couldn't bear bringing this into the main class -- I just don't like imposing object-oriented concepts on a relational database).
First, I'll be implementing extra table information, pretty much in the way I described. This is already well along in the repository, and looks like:
class MyTable(SQLObject): class sqlmeta: table = 'my_funny_table_name' style = MixedCaseStyle() col = StringCol() ...
So every subclass of SQLObject gets its own sqlmeta class. They are buddy classes, with a separate sqlmeta subclass (always with the same name) for each SQLObject subclass. And they are buddy instances too -- anInstance.sqlmeta is an instance of ATable.sqlmeta. Confusing? Hopefully not, I think it makes sense when you are using it.
This sqlmeta class/instance/attribute will hold much of the public API for SQLObject. Your extensions will add custom methods and attributes (/columns) to the SQLObject subclass, but that class will be pretty much yours and yours alone, as all the SQLObject accounting is being moved to sqlmeta.
With this we'll finally add stable, documented APIs for all sorts of introspection, like listing all the columns in a table.
Backward compatibility is being maintained, with settings to control how many warnings you want to get about using the old style of class definitions and attributes. By default there will be lots of warnings, so people new to SQLObject who are working off older documentation will be alerted to the new style early on.
SQLObject now uses a very simple metaclass:
class DeclarativeMeta(type): def __new__(meta, class_name, bases, new_attrs): cls = type.__new__(meta, class_name, bases, new_attrs) if new_attrs.has_key('__classinit__'): cls.__classinit__ = staticmethod(cls.__classinit__.im_func) cls.__classinit__(cls, new_attrs) return cls
This is along the lines of a conservative metaclass, and all the interesting logic is in SQLObject.__classinit__ (a method which I am also trying to whittle down). Hopefully this will make the code seem more accessible -- while it doesn't change much, it simplifies something that many people find intimidating (metaclasses) and moves the bulk of that logic into a much simpler method (__classinit__).
Along the lines of what I proposed for setonce earlier, __classinit__ will check for "magic attributes". Right now it looks specifically for subclasses of Col (which are column descriptions) and a couple other special classes. After this change it will look for a special method on attributes: __addtoclass__, and calls that method with the class the attribute is being bound to, and the name it is being given. That method can replace the attribute. It gets a little complicated, because we usually replace the original object with one that is closely tied to the class it is being bound to -- this way the original object can be reused -- but it really comes down to a fairly simple soClass.addColumn(attributeWeJustCreated).
This will be something that other people can use to extend SQLObject. For instance, there's more kinds of joins, like a situation where two tables are related with some string indicating the type of relation (e.g., a person might be related to an object as an owner, author, watcher, etc). I think these active attributes will be easy to write, and allow people to express some of the things they want to express without adding too many ideas and policies into SQLObject itself.
As well as becoming active attributes, column objects will become descriptors. This means property will be used less, and the dynamically-created lambdas will also go away (they are now just being created with eval(), a bit of a bad smell).
The current way of overriding getters and setters (by defining _get_columnName and _set_columnName) will go away, and instead you'll be able to add methods to the column descriptors. These methods will be a bit easier to understand and use.
Descriptors will also do double-duty as sqlbuilder objects, so you don't have to use MyTable.q.column in queries, instead you can just use MyTable.column.
I also plan to add hooks for various events, like when a row is created, updated, or deleted. So maybe a you could implement something where a row was always updated to indicate the last time the row was editor. Or CASCADE could be implemented as a hook on the delete event for ForeignKey.
This last stuff might not make it into 0.7; I'm still working on the active attributes, and some form of descriptor should happen, but the events might be a stretch.
Anyway, that's the plan I have now, if you are curious about where SQLObject is going.
Sounds great! I'm glad you're going with full-blown descriptors, especially; it makes additional functionality that much easier for developers.
You mentioned:
I also plan to add hooks for various events, like when a row is created, updated, or deleted. So maybe you could implement something where a row was always updated to indicate the last time the row was edited.That's something I've been trying to finagle into the object layer in my ORM lately. The descriptors are great for firing triggers when each value is modified, but not useful for parallel triggers. For example, if you have, oh... let's say a project-management webapp, you want to send a notification to the project manager when a due date is changed. What happens when both the due date and the owner are changed within the same submission? Ideally, there'd be a way to do the updates first and fire any triggers second (that doesn't require the UI developer to manually serialize). I haven't yet found a good idiom for that.
Of course, the "last time edited" could be handled when you flush the objects at the end of the request, but there are many more complicated interactions I've been running into lately...I'd be interested to hear your opinions.
I am using SQLObject for some weeks now and am very pleased with it. I'm happy to see that is actively being developed. Keep up the good work!
would it be a big task (for me?) to create an Oracle connector?
I wouldn't think it'd be hard, but seeing that everyone starts it (or at least says they have started) but doesn't complete it, maybe there's something mysterious and hard about Oracle support. Especially if you ignore things like _fromDatabase (which is fine for the first version of support) it should be very easy indeed.
Yes, it would be a hard job. Oracle doesn't have a way to quote strings (escape special characters), so one needs to pass a list (or dictionary) of parameters along with parametrized query string. This requires changing the way SQLObject generates queries. I've started to work on this, but there is a long road in front of me. Please join if you are really interested to help.
While this will cause a problem for BLOBs and some other types without a SQL literal representation, Oracle does have literal representation of most types of data. It's suboptimal to translate literals into SQL for Oracle to later parse, but it's doable and the way all the other database backends are working at the moment. Most parts of SQLObject would be easy to implement for Oracle, with some border cases that are going to be more difficult.
To a degree its easier here, because SQLObject already centralizes a lot of these operations -- so the descriptors are actually thin delegates back to fixed SQLObject methods. The triggers and events would then also be centrally managed, and would actually be registered during __addtoclass__. There's still some complexity to multiple triggers being fired (and then what order they get fired in, especially when one invalidates the other)... but I'll have to wait to figure that out when the infrastructure is in place to add that complexity ;)
Maybe it's a bit late, but you already don't need to use eval for the dynamically generated lambdas.
e.g. this:
getter = eval('lambda self: self._SO_loadValue(%s)' % repr(instanceName(name)))could be done like this:
getter = lambda self: self._SO_loadValue(repr(instanceName(name)))or even done without using nested_scopes at all:
getter = lambda self, name=repr(instanceName(name)): self._SO_loadValue(name)# Andrew
"I also plan to add hooks for various events, like when a row is created, updated, or deleted. So maybe a you could implement something where a row was always updated to indicate the last time the row was editor. Or CASCADE could be implemented as a hook on the delete event for ForeignKey."
If that sort of thing really matters to your application, then wouldn't you be using a database that had native triggers anyway?
Drawing the line between what you put in app logic and what you put in the database is always tricky. But I tend towards the view that basic data integrity self-defence is more reliable if done in/by the database.
You might put it in the application because: - it's portable across databases (but how often in real life do people decide to switch the database behind a serious application that their business depends on?) - it works for databases that don't support those things natively (but why would you use one of those if data integrity was a serious concern?) - you can see and maintain all your logic in one place
You might put it in the database because: - it's probably probably more efficient. Assume people building databases know more about how to do this sort of stuff quickly and reliably than you (for any likely value of "you") do. - it can't be bypassed by people accessing the same database from a different client application, or even by somebody else writng a different part of the same application
I notice that even MySQL might have triggers soon: http://rootprompt.org/article.php3?article=8289
In general, I agree, a company probably doesn't switch databases very often. I started my personal project using sqlite and moved over to mysql after development was under way. All it took was a change in the connection string ( and some refactoring to use datetime instead of mx.DateTime which doesn't count ). SQLObject's ability to easily switch backend stores helps me a lot - it makes it easier for me to develop and choose a provider when the time comes. But this is probably true more for small efforts than corporate IT infrastructure projects.
If you're writing an in-house app, or one targeted at only one DB, then putting the triggers in the DB can make sense (because you don't change databases often, as you pointed out). But if you're writing an app on top of SQLObject which you then want others to use with many different databases, it's nice to write the triggers once, rather than once for each potential target DB.
Well, like other people said, SQLObject can be used at a lower level than any single deployment -- SQLObject can be part of a project which may get installed anywhere. This just came up for a user: http://www.crummy.com/2005/02/18/0 -- and it will come up all the time for open source developers that distribute projects based on SQLObject.
But even then, database triggers are limited; they can operate on the database, but not otherwise. So, if your dependent object isn't a SQLObject instance then a database trigger won't accomplish anything. E.g., if you want a FileCol which only stores a filename in the database, and that file needs to be deleted along with the row. Or if you have two separate databases that have dependencies across the databases.
And even when you are only dealing with the database, database triggers still aren't sufficient, because they don't give SQLObject any feedback, so it doesn't know how to update its cache. SQLObject, for reasons tied to its very ORMness, has problems when the database gets updated behind its back. I'd like to fix some of those problems (and some of these features could help), but in this case SQLObject could still cache aggressively in the presence of in-process cascades.
Good points, Ian. I think I detect a fairly fundamental difference in worldview/emphasis/(don't say the p*gm word!) between:
- the application as the primary thing and the db as a dumb persistence store
versus ...
- the data as the primary thing and the dbms as its primary guardian; triggers (etc) as the immune system that protect it from things malicious/miguided applications might try to get up to.
It's a design decision about at what layer in the stack you want to have your basic data integrity defence mechanisms, with different valid answers in different circumstances. Although what you seem to be saying/implying is that SQLObject won't be able to cope if you put them anywhere other than in the app's persistence layer. I would expect that (with all due respect) to be very significantly slower and less reliable than native triggers in any mature production rdbms - especially if the app isn't running on the same machine. And even if you can live with that, what if you aren't the only application - or the only instance of the same application - that's talking to the same database?
So you would appear to be limited to one instance of one application that "owns" the database entirely. Which of course is perfectly adequate in many circumstances, but severely limits what you can do if you want to load balance your app / run with existing production databases that already have integrity protections in place / etc.
Martin Fowler called one style an Application Database (what SQLObject prefers) vs. an Integration Database (where the database is authoritative and the communication medium for multiple applications).
I should really write a more thorough summary of why it's hard to be reasonably efficient with an ORM while also being compatible with an Integration Database style. Not impossible -- it's just a matter of what your expectations are. Hmm... I've never properly written up the performance issues of an ORM; I should do that so I can refer to it at times like these...