THE PRINCE OF EGYPT A movie review by Joe Barlow (c) Copyright 1999
STARRING: Val Kilmer, Ralph Fiennes, Sandra Bullock, Patrick Stewart DIRECTORS: Brenda Chapman, Steve Hickner, Simon Wells WRITER: Philip LaZebnik RATED: PG RELEASED: 1998 SEEN AT: Imperial Cinema, Cary NC
RATING: *** 1/2 (out of a possible ****)
Even apart from the possible religious controversey, Dreamworks has taken a serious financial risk with their first animated release, "The Prince of Egypt." Not only have they done the unthinkable (challenge the supremacy of "The Mouse" in the field of feature-length animation), they've chosen a topic with the potential to offend as many as it entertains. There's also the strong possibility that the film's target audience, children, may not wish to attend a "religious" movie, which often has the stigma of boredom attached to it, even when animated.
But never fear: Dreamworks has created an entertaining film that can be enjoyed even by those who have little interest in the Bible. Setting aside the stoic morality lessons that religious epics so often attempt to convey, "The Prince of Egypt" is a fun, fast gallop through the Old Testament's Book of Exodus, covering the life of Moses beginning with his mother's desperate attempt to save his life, and culminating with his deliverance of the Ten Commandments to the Hebrews. But although the movie's tone is often light-hearted and comical, it finds a striking balance with the seriousness and drama that source material of this nature demands. It's a delicate high-wire act, but the film doesn't stumble.
Moses (voiced by Val Kimer) and Ramses (voiced by Ralph Finnes, whose career seems to be recovering nicely after "The Avengers") are sons of the Pharoah Seti (an excellent vocal performance from Star Trek's Patrick Stewart). Wild and carefree, the two boys are the best of friends, in addition to being brothers. This changes after Moses learns the truth from his sister Miriram (Sandra Bullock): he is not the true son of the Pharoah after all. Leaving behind the only life he has ever known, Moses wanders into the desert and finds contentment and happiness with a band of gypsies. Eventually, however, God speaks to him and reveals Moses's true mission: free the Hebrews from the grip of the tyranical new Pharoah... who happens to be none other than his former "brother," Ramses. This is the stuff of which great drama is made, and the film wisely concentrates the majority of its screen-time with the difficult relationship between these two young men, each uncomfortable with their new animosity... but both nonetheless unyielding in their beliefs. The vocal performances by Kilmer and Finnes are excellent, with each properly conveying the tone and frustration that each character possesses.
Visually, "The Prince of Egypt" is overflowing with stunning moments and incredible imagery; in fact, I believe that it contains the highest quality animation I've ever seen in an American film. The alternating seriousness and comedy works very well, each providing an intriguing counterpoint to the other, yet never detracting from the epic qualities of the story. (And to my great delight, Dreamworks didn't feel the need to throw in any cute, talking animals with a fondness for singing and dancing.) The influence of Disney is felt in one significant way, however: musical numbers, and plenty of 'em. Although they're not bad when taken on their own, I observed that on a few occasions they greatly hindered the story's pacing. A minor flaw, perhaps, but I frequently found myself waiting for the tunes to end so I could get back to the actual plotline, which interested me far more.
"The Prince of Egypt" is nonetheless a cinematic triumph, offering proof that Disney doesn't have a monopoly on quality American animation. Parents should be aware, however, that this movie is rated "PG," rather than the tamer "G" that most Disney films receive. It has a number of intense moments which could conceivably scare younger members of the family: the slaughtering of the Egyptian first-borns gave *me* chills, as did Moses's eerie "hyroglyphics" dream sequence; also, some of the children at the screening I attended seemed quite frightened by the sight of Pharoah's hordes descending down upon the Hebrews at the Red Sea. You're the best judge of what your kids can handle, but do be aware that moments of the film are quite livid. But if you can handle it, you're in a for a treat.
E-Mail<EMAIL_ADDRESS>Joe Barlow on Film: http://www.ipass.net/~jbarlow/film.htm
If you'd like to receive new film reviews by e-mail, please write to the above address and ask to be put on my mailing list. Or, you can subscribe directly from my web page. Thanks.
-----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Split Wizard
The Wizard does not have the strength to split the bills without the power of Javascript.


Hi! Welcome to Trequila
As you can see, our website is not complete yet but don't worry.
You can contact us at<EMAIL_ADDRESS>Thanks for visiting! :)


Recover judgment debt
The balance outstanding on the judgment is £1,643.20. The defendant was ordered to pay instalments of £120 every week.
View amount breakdown
| Amount breakdown | Amount |
|---|---|
| Claim amount | £1,500 |
| Interest to date | £68.20 |
| Original claim fee | £75 |
| Minus amount already paid | £200 |
| Balance outstanding | {% if data['radio-indent-group2']=="Yes" %}£1,443.2{%else%}£1,643.20{%endif%} |
How much do you want to try to recover?
{% include 'prototypes/prototype-feb-2019/includes/contact.html' %} {% endblock %}


CMS
Something short and leading about the collection below—its contents, the creator, etc. Make it short and sweet, but not too short so folks don't simply skip over it entirely.
{% block content %}
{% endblock %}
Something short and leading about the collection below—its contents, the creator, etc. Make it short and sweet, but not too short so folks don't simply skip over it entirely.


We at trajans.market Inc. (trajans.market, we, us and our) know that our users (you, your and yourself) care about how your personal information is used and shared, and we take your privacy seriously. Please read the following to learn more about our Privacy Policy. By visiting or using the www.trajans.market website and domain name, features, content, mobile applications, and any other services we offer from time to time in connection with any of the foregoing (collectively, the Website), you agree to the practices and policies set forth in this Privacy Policy, and you hereby acknowledge and consent to our collection, use, and sharing of your information as described in this Privacy Policy. Any external links to other websites are clearly identifiable as such, and we are not responsible for the content or the privacy policies of these other websites.
1. What does this privacy policy cover?
This Privacy Policy covers our treatment of personally identifiable information (Personal Information) that we gather when you are accessing or using our Website. This policy does not apply to the practices of companies that we do not own or control, or to individuals that we do not employ or manage, even if you have accessed the websites or services of those companies through our Website.
We do not knowingly collect or solicit personal information from anyone under the age of 18 or knowingly allow such persons to register for the Services (as that term is defined in our Terms and Conditions). If you are under 18, please do not attempt to register for the Services or send any information about yourself to us, including your name, address, telephone number, or email address. No one under age 18 may provide any personal information to us or on the Services. If we learn that we have collected personal information from a persons under age 18 without verification of parental consent, we will delete that information as quickly as possible. If you believe that we might have any information from or about a persons under 18, please contact us at<EMAIL_ADDRESS>2. What information does trajans.market collect?
We gather various types of Personal Information from our users, as explained more fully below. We may use this Personal Information to, among other things, personalise and improve our services, allow our users to set up a user account and profile, contact users, fulfill your requests for certain products and services, analyse how users utilise the Website, or as otherwise set forth in this Privacy Policy. We may share certain types of Personal Information with third parties (as described in this Section and in Section III below). We collect the following types of information:
2.1 Information You Provide to Us:
We receive and store any information you knowingly provide to us. For example, we collect Personal Information such as your name, username, phone number, credit card and other billing information, email address, shipping address, and your third-party account credentials (for example, your log-in credentials for Facebook). We may also collect information you supply to us regarding your personal preferences and interests.
If you access the Service through an external third-party application, such as Facebook, we may receive some data from those connected third-party applications. Connecting your account to third-party applications or services is optional, and when you connect your account to an external app, you will be given the opportunity to grant permission. You can revoke your permission under your account settings.
We may receive or collect information (for example: an email address) about a person who is not yet a registered trajans.market member (a non-member) in connection with certain trajans.market features, including but not limited to: a non-member subscribing to a trajans.market newsletter, a member inviting a non-member to visit the Site, a non-member engaging in a transaction, or a member sending a gift card code to a non-member. Non-member information is used only for the purpose it was originally submitted to us. A non-member can contact trajans.market support if they do not want us to retain their information.
We may anonymise your Personal Information so that you cannot be individually identified and provide that anonymised information to our partners. For example, we allow advertisers to choose the demographic information of users who will see their advertisements and you agree that we may use any of the information we have collected from you in non-personally identifiable form to allow our advertisers to select the appropriate audience for those advertisements. We might use the fact you have purchased or inquired about a certain brand of apparel, for instance, to show you advertisements for the company that sells that brand, but we will not disclose to that company your identity.
2.2 Information Collected Automatically:
Whenever you interact with our Website, we automatically receive and record information on our server logs from your browser including your IP address, cookie information, and the page you requested. Cookies are identifiers we transfer to your computer or device that allow us to recognise your browser or device and tell us how and when pages in our Website are visited and by how many people. You may be able to change the preferences on your browser or device to prevent or limit your computer's or device's acceptance of cookies, but doing so may prevent you from taking advantage of our Website's best features. Our advertising partners may transmit cookies to your computer or device when you click on ads that appear on our site. This Privacy Policy does not cover cookies delivered to you by any of our advertisers.
When we collect usage information (such as the numbers and frequency of visitors to the Website and to which pages within the Website), we only use such data in aggregate form, in a manner that assures your anonymity. We may provide this aggregate usage information to our partners; our partners may use such information to understand how often and in what ways people use our Website, so that our partners, too, can endeavor to provide you with an optimal online experience. For example, we may place a cookie on your device that records what products you have viewed on our Website, and then provide that information, in non-personally-identifiable form, to a third party website, to allow such website to show you ads for similar products that are available from us or from third parties.
We may also deliver a file to you through the Website (known as a "web beacon") from an advertising network we have contracted with. Web beacons allow advertising networks to provide anonymised, aggregated auditing, research and reporting for us and for advertisers. Web beacons also enable ad networks to serve targeted advertisements to you when you visit other websites. These beacons may, for example, log that you have viewed a certain product on our Website, and then show you an ad for similar products when you browse to another website. Because your web browser must request these advertisements and web beacons from the ad network's servers, these companies can view, edit, or set their own cookies, just as if you had requested a web page from their site. Many ad networks participate in the Network Advertising Initiative (NAI), a cooperative of online marketing and analytics companies committed to building consumer awareness and establishing responsible business and data management practices and standards, and such NAI members may allow you to opt-out of cookies or beacons they deliver. Again, we do not control the policies of any third parties, including advertising networks.
We do not honor do-not-track signals from Internet browsers or other consumer choice mechanisms regarding the collection of behavioral tracking data.
2.3 E-mail and Other Communications:
We may contact you, by email or other means. For example, we may send you promotional offers on behalf of other businesses, or communicate with you about your use of the Website. Also, we may receive a confirmation when you open an email from us. If you do not want to receive email or other mail from us, please indicate your preference by changing your account settings accordingly.
3. Will trajans.market share any of the personal information it receives?
We neither rent nor sell your Personal Information in personally identifiable form to anyone. We share your Personal Information in personally identifiable form with third parties only as described below:
3.1 Affiliated Businesses and Third Party Websites We Do Not Control:
In certain situations, businesses or third party websites were affiliated with may sell items or provide services to you through the Website (either alone or jointly with us). You can recognise when an affiliated business is associated with such a transaction or service, and we will share your Personal Information with that affiliated business only to the extent that we deem it related to such transaction or service. One such service may include the ability for you to automatically transmit information from your trajans.market account to an account on a third party website or service, such as Facebook. We have no control over the policies and practices of third party websites or businesses as to privacy or anything else, so if you choose to take part in any transaction or service relating to an affiliated website or business, please review all such business's or websites policies.
3.2 Agents:
We employ other companies and people to perform tasks on our behalf and need to share your information with them to provide products or services to you. Unless we inform you otherwise, our agents do not have any right to use the Personal Information we share with them beyond what we deem necessary to assist us in performing such tasks.
3.3 Other trajans.market Users:
As part of the buying and selling process, we will facilitate the sharing of information between the two members involved in the transaction. As part of the buying or selling process, you may obtain another trajans.market user's email address, shipping address, payment information, and/or other information. As described in trajans.market's Terms and Conditions, you have a limited license to use this information only for trajans.market-related communications or for trajans.market-facilitated transactions. We have not granted you a license to use the information for unsolicited commercial messages or unauthorised transactions. Without express consent from that person, you must not add any trajans.market user to your email or physical mailing list or store or misuse any payment information.
3.4 User Profiles and Content:
Certain user profile information, including without limitation a user's username and the image content that such user has uploaded to the website may be displayed to other users to facilitate user interaction within the Website or address your request for our services. Any content you upload to your public user profile, along with any Personal Information or content that you voluntarily disclose online in a manner other users can view (on discussion boards, in messages and chat areas, etc.) becomes publicly available, and can be collected and used by others. Your username may also be displayed to other users if and when you post comments or upload images through the Website and other users can contact you through such comments. If you sign into the Services through Facebook Connect, your list of friends from Facebook may be automatically imported to the Services, and such friends, if they are also registered users of the Services, may be able to access certain non-public information you have entered in your Services user profile. Again, we do not control the policies and practices of any other third party site or service.
3.5 Business Transfers:
We may choose to buy or sell assets. In these types of transactions, customer information (which may include your Personal Information) is typically one of the business assets that is transferred. Also, if we (or substantially all of our assets) are acquired, or if we go out of business or enter bankruptcy, Personal Information would be one of the assets transferred to or acquired by a third party.
3.6 Protection of trajans.market and Others:
We may release Personal Information when we believe in good faith that release is necessary to comply with laws; enforce or apply our conditions of use and/or other agreements; or protect the rights, property, or safety of trajans.market, our employees, our users, or others. We may exchange information with other companies and organisations (including governmental authorities) for fraud protection and credit risk reduction.
3.7 With Your Consent:
Except as set forth in this Privacy Policy, you will be notified when your Personal Information may be shared with third parties, and will be able to prevent the sharing of this information.
4. Is personal information about me secure?
Your account is protected by a password for your privacy and security. If you access your account via Facebook Connect, you may have additional or different sign-on protections through Facebook. You need to prevent unauthorised access to your account and Personal Information by selecting and protecting your password (or other sign-on protections) appropriately and limiting access to your computer or device by signing off after you have finished accessing your account.
We endeavor to protect the privacy of your account and other Personal Information we hold in our records, but we cannot guarantee complete security. Unauthorised entry or use, hardware or software failure, and other factors may compromise the security of user information at any time.
The Website may contain links to other sites. We are not responsible for the privacy policies and/or practices on other sites. When following a link to another site you should read that site's privacy policy.
5. What personal information can I access?
Through your account settings, you may access, and, in some cases, edit or delete the following information you've provided to us:
name and password;
email address;
shipping and billing information;
user profile information and User Content, including images you have uploaded to the site
The information you can view and update may change as the Website changes. If you have any questions about viewing or updating information we have on file about you, please contact us at<EMAIL_ADDRESS>6. What data does trajans.market retain?
We will retain your information only for as long as is necessary or your account is active or as needed to provide you services. If you no longer want us to use your information to provide you services, you may close your account. We will retain and use your information as necessary to comply with our legal obligations, resolve disputes, and enforce our agreements.
You may inform us of any changes or requests in regards to your personal data, and in accordance with our obligations under local data protection law, we may update or delete your personal data accordingly.
7. What choices do I have?
You can always elect not to disclose information to us. However, please keep in mind that we may need some information to allow you to register with us or to take advantage of some or all of our features, and if you choose not to provide that information, your ability to use our Website and services may be limited.
You may be able to add, update, or delete information as explained in Section V above. When you update information, however, we may maintain a copy of the unrevised information in our records. You may request deletion of your account by visiting your account settings. Please note that some information may remain in our private records after your deletion of such information from your account. We may use any aggregated data derived from or incorporating your Personal Information even if you update or delete it, but we will not use that information in a manner that would identify you personally.
If you do not wish to receive email or other mail from us, please change your account settings accordingly. Please note that if you do not want to receive legal notices from us, such as this Privacy Policy, those legal notices will still govern your use of the Website, and you are responsible for reviewing such legal notices for changes.
8. Changes to this privacy policy.
We may amend this Privacy Policy from time to time. Use of information we collect now is subject to the Privacy Policy in effect at the time such information is used. If we make changes in the way we use Personal Information, we will notify you by posting an announcement on our Website or contacting you directly via email or other means. You are bound by any changes to the Privacy Policy when you use the Website after such changes have been first posted.
9. Questions or concerns
If you have any questions or concerns regarding our privacy policies, please send us a detailed message to<EMAIL_ADDRESS>We will make every effort to resolve your concerns.


{{- define "title" -}} Home {{- end -}} {{- define "description" -}} GoThrough hosts a searchable index of exported members in the Go standard library and a selection of hosted packages. {{- end -}} {{- define "head" -}} {{- end -}} {{- define "query" -}} {{- end -}} {{- define "body" -}}
GoThrough hosts a searchable index of exported members in the Go standard library and a selection of additional packages.
You can use and combine the following tags to refine and customize your query.
| count | c | Maximum number of results returned (default 32). | reader count:4 |
| package | p | Only show results from this package. | package:regexp p:strings replace |
| -package | -p | Don't show results from this package. | status -p:http |
| type | t | Only show results of this type (const, var, function, interface). | reader type:interface |
| -type | -t | Don't show results of this type (const, var, function, interface). | err -type:function -t:interface |


ROBODOC® System
Min Yang Jung | 31 Dec 2016When I decided to work on the software system safety as my PhD thesis topic, it didn’t take long before I realized safety in the medical robotics domain had not yet been formulated as a well-defined research problem. Although virtually all papers in the medical robotics domain mention (the importance of) safety, it has been mostly considered in the application- or system-specific context, rather than as a system property that requires systematic approaches.
So I spent quite a bit of time – almost a year – for literature review in various areas such as software engineering, component-based software engineering, system safety engineering, safety- and mission-critical application domains, dependable computing domain, and so on. Two major findings (I’ll write another post that overviews those related domains later):
- Within medical robotics, there is a lack of prior work that specifically focus on the safety of medical robots.
- Outside medical robotics, Safety has been already recognized as one of crucial system properties and as such there is a substantial body of work around it.
This was a good news to me in that I had room for contributions, but at the same time was not a good news because there were not much of prior work that I could refer to for my research.
Fortunately, there was one medical robot system, of which many aspects are relatively well documented and published in the academic medical robotics literature: The ROBODOC® system system, an orthopedic surgical robot system. Starting from its history, the topics they cover include user-driven system design requirements, an overall system architecture, design rationale, safety design principles, and some of engineering details. Even though most of these papers were published in the 90’s, I personally learned a lot from those articles, which later became my primary resource for my own research on safety, including my PhD dissertation. So I thought a list of those papers with the history of the ROBODOC system may be useful for those who are curious about ROBODOC, who are interested in safety in general, or who are (about to) working on safety as a research topic. The list of the literature that I reviewed includes Taylor et al. (1990, 1991, 1994, 1996), Kazanzides et al. (1992, 1993, 1995, 1996, 1999), Mittelstadt et al. (1993, 1996), and Cain et al. (1993). For a complete list, please refer to the Reference section at the bottom of this article.
DISCLAIMER: This article is an excerpt of my PhD dissertation (Section 6.2.1), which was proofread by Dr. Peter Kazanzides and Dr. Russell H. Taylor. Dr. Kazanzides is a co-founder of the Integrated Surgical System (ISS), a manufacturer of the ROBODOC system, and was the Director of Engineering of ISS. Dr. Taylor designed and prototyped an earlier version of the ROBODOC system for a veterinary orthopedic surgery at the IBM Research in the late 80’s.
Overview of the ROBODOC System
The ROBODOC® system has been developed to increase the accuracy and efficacy of surgical procedures such as cementless Total Hip Replacement (THR) surgery and Total Knee Replacement (TKR) surgery by enabling surgeons to precisely specify the desired prosthesis placement in a preoperative CT scan of the patient and then use the robotic system to accurately machine the bone to achieve that plan.
It began as a joint project between the University of California, Davis and IBM Research. The canine system (alpha prototype) was developed for canine THR in a well-controlled, supervised research environment, i.e., under the active supervision of the developing engineers. It was first clinically used in 1990 for canine patients at a veterinary hospital in Sacramento, California and performed canine surgeries. This alpha prototype went through fundamental changes and improvements to evolve into a beta (investigational) medical device that was operated by surgical teams –- without engineers –- for human clinical trials at multiple clinical sites. The beta version of ROBODOC was the subject of an FDA-authorized, multi-center clinical trial in the United States, and performed over 200 surgeries at a hospital in Frankfurt, Germany. It was then further developed as a commercial-level product to be used in Europe and this required an architectural change from a centralized architecture to a distributed architecture.
The following figure shows the ROBODOC System. The two main components of the ROBODOC System are the ORTHODOC™ Preoperative Planning System (ORTHODOC) and the ROBODOC Surgical Assistant (ROBODOC). ORTHODOC allows the surgeon to develop a preoperative plan that ROBODOC can execute. The two inputs to ORTHODOC are a Computed Tomography (CT) scan of the patient’s femur and a set of implant models based on data from the implant manufacturers. Using implant models and a three-dimensional model of the femur constructed from the CT data, the surgeon visually determines an appropriate implant model with its precise location. Once the plan is finalized, the preoperative plan is recorded and transferred to ROBODOC via a transfer medium (tape or CD).
ROBODOC reads the preoperative plan from the transfer medium and machines a cavity for the implant in the femur according to the plan. To precisely execute the plan, it is required to register the patient’s femur in the preoperative plan with the intraoperative physical reality (i.e., the robot’s workspace coordinates). Calibration of the robot kinematic parameters and the cutting tool’s dimensional parameters also play a vital role in achieving high dimensional accuracy. Based on clinical input, the specification of the robot’s placement accuracy (deviation from the preoperatively planned position) is less than 1.0 mm, and that of the dimensional accuracy (deviation of the machined shape from its ideal dimensions) is less than ±0.4 mm on a cross-section (or ±0.2 mm on each side).
Safety Features of ROBODOC
The principal safety requirements of ROBODOC were defined by a surgeon, who was a user of the system, as follows:
- The robot should never “run away”: No single-mode hardware failure or system error should cause the application software to lose control of the robot motions.
- The robot should never exert excessive force on the patient: Any cutting force substantially more than needed means something may be wrong and the robot better stop its current motion.
- The robot’s cutter should stay within a pre-specified positional envelope relative to the volume being cut: A systematic positional shift in the placement or shape of the hole should be prevented.
- The surgeon must be in charge at all times: The system must provide the surgeon with timely information about its current status and the surgeon must be able to stop motions at any time.
A set of safety features distributed throughout the system were designed to achieve these principle safety requirements. The following presents a partial list of the safety features of ROBODOC based only on the published, academic literature.
- System integrity monitoring (with redundant sensors): The real-time control loop periodically monitors system integrity, such as tolerance checking of primary and redundant encoders at each joint, with the capability to turn off the robot arm.
- Use of state variables for error handling : State variables are defined to represent application-specific procedural flow and are used for error or exception handling.
- Dedicated processor for the safety system : The safety system runs on a separate processor to isolate it from errors in other subsystems and has a direct hardware interface to power othe system.
- Force/torque checks with two thresholds : Force and torque feedback from the force sensor are monitored against two thresholds, PAUSE (1.5 kg-f) and STOP (3.0 kg-f). PAUSE halts all robot motion and turns off the cutter, whereas STOP removes power from both the robot and the cutter.
- Speed limiter (low speed): The low-level software implements the speed limiter. It operates on the output of the trajectory generation functions and limits the robot’s speed and torque. The rationale of this safety feature is that the surgical staff can stop the robot before any hazard occurs if the robot is slow and weak.
- Safety volume (dynamic constraints): During cutting, the software verifies that the cutter tip is within a pre-planned safety volume, with a 3 mm margin for error. The safety volume is derived from the prosthesis geometry, but is independent from the file containing the cutting paths.
- Notification of exceptions to application : Any reflex action initiated by a safety system leads to an exception to the application which interrupts the normal procedural flow and invokes a handler function for error recovery.
- Error detection : Data integrity checks (e.g., if there is any corruption of critical data), data rationality checks (e.g., if case-specific data are reasonable), detection of procedural errors (e.g., if surgeons make procedural errors that can compromise both safety and system performance).
- Startup diagnostics : During start up, all safety- and performance-related components are verified to make sure that they are functioning within specified tolerances.
- User oversight with emergency pause/stop : An external custom pendant with five buttons, including emergency pause and stop, helps surgeons to interact with the system and a graphical display in the operating room provides the current status of the surgical procedure.
References
ROBODOC Literature
This is a list of the academic literature on the ROBODOC System that I have reviewed with focus on its system design and safety features.
- R. H. Taylor, P. Kazanzides, B. Mittelstadt, and H. Paul. Redundant consistency checking in a precise surgical robot. In Proc. of the 12th Annual Intl. Conf. of the IEEE, pages 1933–1935, Nov. 1990.
- R. H. Taylor, H. Paul, P. Kazanzides, B. Mittelstadt, W. Hanson, J. Zuhars, B. Williamson, B. Musits, E. Glassman, and W. Bargar. Taming the bull: Safety in a precise surgical robot. In Intl. Conf. on Advanced Robotics (ICAR), volume 1, pages 865–870, Jun. 1991.
- P. Kazanzides, J. Zuhars, B. Mittelstadt, and R. Taylor. Force sensing and control for a surgical robot. In IEEE Intl. Conf. on Robotics and Automation (ICRA), volume 1, pages 612–617, May 1992.
- P. Kazanzides, J. Zuhars, B. Mittelstadt, B. Williamson, P. Cain, F. Smith, L. Rose, and B. Musits. Architecture of a surgical robot. In IEEE Intl. Conf. on Systems, Man and Cybernetics, volume 2, pages 1624–1629, Oct. 1992.
- B. Mittelstadt, P. Kazanzides, J. Zuhars, P. Cain, and B. Williamson. Robotic surgery: achieving predictable results in an unpredictable environment. In Intl. Conf. on Advanced Robotics (ICAR), volume 11, pages 367–372, 1993.
- P. Cain, P. Kazanzides, J. Zuhars, B. Mittelstadt, and H. Paul. Safety considerations in a surgical robot. In Proc. of 30th Annual Rocky Mountain Bioengineering Symp., volume 29, page 291, Apr. 1993.
- P. Kazanzides, B. Mittelstadt, J. Zuhars, P. Cain, and H. Paul. Surgical and industrial robots: Com- parison and case study. In Proc. of the Intl. Robots and Vision Automation Conf., pages 1019–1026, Detroit, MI, Apr. 1993.
- R. H. Taylor, B. Mittelstadt, H. Paul, W. Hanson, P. Kazanzides, J. Zuhars, B. Williamson, B. Musits, E. Glassman, and W. Bargar. An image-directed robotic system for precise orthopaedic surgery. IEEE Trans. on Robotics and Automation, 10(3):261–275, Jun. 1994.
- P. Kazanzides, B. Mittelstadt, B. Musits, W. Bargar, J. Zuhars, B. Williamson, P. Cain, and E. Carbone. An integrated system for cementless hip replacement. IEEE Engineering in Medicine and Biology Magazine, 14(3):307–313, May/Jun. 1995.
- P. Kazanzides, P. W. Cain, and H. A. Wasti. Distributed architecture for a fail-safe robot system. In Proc. of the Signal Processing Applications Conference & Exhibition (DSPx), San Jose, CA, Mar. 1996.
- R. H. Taylor, B. D. Mittelstadt, H. A. Paul, W. Hanson, P. Kazanzides, J. F. Zuhars, B. Williamson, B. L. Musits, E. Glassman, and W. L. Bargar. An Image-Directed Robotic System for Precise Orthopaedic Surgery, chapter 28, pages 379–396. Computer-Integrated Surgery. MIT Press, Cambridge, MA, 1996.
- B. D. Mittelstadt, P. Kazanzides, J. F. Zuhars, B. Williamson, P. Cain, F. Smith, and W. L. Bargar. The Evolution of a Surgical Robot from Prototype to Human Clinical Use, chapter 29, pages 397–407. Computer-Integrated Surgery. MIT Press, Cambridge, MA, 1996.
- P. Kazanzides. Robot Assisted Surgery: The ROBODOC (R) Experience. In Intl. Symp. on Robotics (ISR), volume 30, pages 281–286, Tokyo, Japan, 1999.
Articles on ROBODOC Safety
In case you are interested in further information of the ROBODOC safety design, below are a couple additional articles for reference.
- M. Y. Jung. State-based Safety of Component-based Medical and Surgical Robot Systems. PhD thesis, The Johns Hopkins University, Baltimore, Maryland, USA, May. 2015.
- M. Y. Jung, R. H. Taylor, and P. Kazanzides. Safety Design View: A conceptual framework for systematic understanding of safety features of medical robot systems. In IEEE Intl. Conf. on Robotics and Automation (ICRA), pages 1883–1888, 2014.


This webpage was created by Justin Bishay.
Leaflet and Plotly.js were used to make the visualizaion.
The cholera data was provided by Dr. Jason Leigh.
(click anywhere to close)
1854 Cholera Outbreak in London
Deaths by Date
Deaths by Age and Sex
UK Census
Map of Deaths and Pumps
About
Attacks and Deaths By Date
Deaths by Age and Sex
UK Census Data
Deaths and Pump Locations


This is an ecology simulator. It's very much in Work In Progress right now so it will be complete when it will be complete.
I love ecological equilibilirums. They give me joy for some reason. So I am building this simle code. If you want to help me you can tweet at me: @ysfbekts


| lavExport {lavaan} | R Documentation |
Export a fitted lavaan object to an external program.
lavExport(object, target = "lavaan", prefix = "sem", dir.name = "lavExport", export = TRUE)
object |
An object of class |
target |
The target program. Current options are |
prefix |
The prefix used to create the input files; the name of the input file has the pattern ‘prefix dot target dot in’; the name of the data file has the pattern ‘prefix dot target dot raw’. |
dir.name |
The directory name (including a full path) where the input files will be written. |
export |
If |
This function was mainly created to quickly generate an Mplus syntax file to
compare the results between Mplus and lavaan. The target "lavaan"
can
be useful to create a full model syntax as needed for the lavaan()
function. More targets (perhaps for LISREL
or EQS
) will be added
in future releases.
If export = TRUE
, a directory (called lavExport
by default) will
be created, typically containing a data file, and an input file so that the
same analysis can be run using an external program. If export = FALSE
, a
character string containing the model syntax only for the target program.
HS.model <- ' visual =~ x1 + x2 + x3 textual =~ x4 + x5 + x6 speed =~ x7 + x8 + x9 ' fit <- cfa(HS.model, data=HolzingerSwineford1939) out <- lavExport(fit, target = "Mplus", export=FALSE) cat(out)


This news feature from the future is MONTAG FICTION #013
J. K. MITTWOCH Associated Press November 6, 2027
CAPE CANAVERAL, FL. (AP) – The eight richest people on the Earth will leave its atmosphere at noon today.
They represent half the wealth of the entire planet and more than half of humanity's hope for the future. If all goes according to plan, they will pave the way for the entire human race to take to the stars. If anyone can do it, these men can.
The billionaires' ship should dock with Melon Husk's extraorbital space station colony within the year. Once settled in space, they intend to tackle the problems of Earth by pooling their resources and to return within the century with solutions to our political, environmental, and economic problems.

Gill Bates, 72, will leave behind his 66,000 square foot mansion overlooking Lake Washington, in favor of 165.8 cubic meters of living and working space in Husk's space laboratories. Belinda and the remainder of the terrestrial Bates clan will continue his philanthropic work in his absence. When asked about his plans for the trip, Bates said: "I'm going to give Husk a piece of my mind up there, I told him robot supersoldiers were a terrible idea."
Business magnate Barren Wuffett, 97, would normally be disqualified for spaceflight due to his advanced age, but after a 2012 bout with prostate cancer, was found to have abnormally high immunity to radiation. After a battery of tests found that his physiological responses were on par with invertebrates such as cockroaches, he has agreed to periodic testing of his personal gene expressions under increasing doses of cosmic radiation. When asked for comment about this risk to his personal health and safety, Wuffet chuckled, "Foolish mortals, in Husk's space laboratories I will become as a god!"
Biff Jezos, 63, after merging Half Foods and Blamazon Drones to create Drone Foods, has invested heavily in nanotechnology which will benefit him and his companions in space, an entirely new culinary frontier. The Jezos bots are semi-autonomous body-safe nano drones carrying artificial scent particles that will fly through their mouths and noses during meals, convincing them the rehydrated pastes and cubes they consume taste of comfort foods such as peanut butter and fried chicken, as well as luxuries they have been accustomed to such as lobster, caviar, and foie gras. When asked about his favorite flavor, Jezos cried, "I can't wait to taste the flesh of the youth again."
The mysterious Spanish billionaire Omancio Artega, 91, who built his fortune on the Zaza retail empire, converted an entire subdivision of his clothing manufacturing conglomerate to create custom space-worthy garments for the crew. Which means Zork Muckerberg, the youngest intergalactic billionaire at 43, will have to abandon his wardrobe of grey t-shirts and hoodies in favor of the mandatory skin-tight, temperature-controlled synthetic onesies. Muckerberg remarked, "I can always put a hoodie on over it, right?"
"I can't wait to get to space and start growing new bones!"
Carl Swim Hulu, 87, who owns almost all telecommunications in Latin America, says he will miss his six children, who will continue to manage his investments in his absence. Barry Bellison, the 83-year-old CEO of the Delphi corporation, said "I can't wait to get up to space and start growing new bones!" When asked to clarify what he meant by "new bones," he added, "You've got no idea how many extra bones Husk can stuff in these meat sacks," and refused to elaborate further.
Snarles Choch, 92, stated his interest in developing new energy technologies in space, "to prove global warming was a setup.  Bwahahahaha!"
For the last two years, the economies of several small countries have been devoted to preparing their mission to the stars. However, some speculate they have no real plans to return. And if they do return, they may no longer be humans as we know them.
Brichard Ransom will christen the Virgin Intergalactic ship Safina by breaking a bottle of champagne over it before its launch at Cape Canaveral this afternoon, during which he will stare into the twin flames of the departing ship's rocket boosters and whisper, "God help us all."
Copyright 2027 The Associated Press


Introduction to Moose
Dave Rolsky
http://www.urth.org/~autarch/intro-to-moose.tar.gz
Introduce Yourselves
- Your name
- What you do with Perl
- Why you're here today (optional)
Moose Summed Up
- Declarative OO sugar
- Introspectable
- Extensible (hundreds of MooseX::* on CPAN)
- Community approved (2,300+ downstream dependents on CPAN)
Moose Background
- Created by Stevan Little, first released in 2006
- Moose builds on Perl 5's native OO
- Borrows ideas from other languages, notably Perl 6
- Provides semantics for common operations
Part 0: Moose Concepts
Classes
-
Classes have ...
- Attributes
- Methods
- Superclasses
- Method modifiers
- Constructor and destructor
- One metaclass object
- Classes do roles
Class Example
package Person;
use Moose;
- Poof, a Moose-based class!
Attributes
- Aka property, slot, field, member variable
- A piece of data owned by an object
Attributes
-
Attributes have ...
- Mutability (read-only vs read-write)
- An optional type
- Accessor methods
- Delegation methods
- Optional default value
- Many more features
- Stored in the object, but don't worry about that
Attribute Example
package Person;
use Moose;
has first_name => ( is => 'ro' );
Methods
- Nothing fancy here, just Perl subroutines
package Person;
use Moose;
sub greet { ... }
Roles
- Classes do (or consume) roles
- Similar to mixins and Java interfaces
Roles
- Like classes, can have attributes, methods, do roles
- Roles can require methods
- Roles are composed (flattened) into classes
Role Example
package HasPermissions;
use Moose::Role;
has is_admin => ( is => 'rw' );
Role Example
And then ...
package Person;
use Moose;
with 'HasPermissions';
Method Modifiers
- AKA advice
- "Before foo(), do this first"
- "Do this after foo()"
- "Put this code around foo()"
Before and After
before 'foo'
=> sub { warn 'About to call foo()' };
after 'foo'
=> sub { warn 'Leaving foo()' };
Around
around 'foo' => sub {
my $real_foo = shift;
my $self = shift;
warn 'Just before foo()';
my @return =
$self->$real_foo( @_, bar => 42 );
return (
@return,
'modify return values'
);
};
Type Constraints
- NOT A FULL-BLOWN TYPE SYSTEM!
- But still darn useful
- Constrain attribute values
- Coerce from other types
Type Constraint Example
package Person;
use Moose;
has weight => (
is => 'ro',
isa => 'Int',
);
# kaboom
Person->new( weight => 'heavy' );
Delegation
- Attributes can define delegations
- Lets you hide some implementation details
- Fewer objects to chase around
Delegation
package Person;
use Moose;
has blog_uri => (
is => 'rw',
isa => 'URI',
handles => { 'blog_host' => 'host' },
);
$person->blog_host;
# really calls $person->blog_uri->host
Constructors
- Moose creates
new()
for you
- Provide an optional
BUILDARGS()
and BUILD()
Destructors
- Provide an optional
DEMOLISH()
Moose Meta-API
- Answers questions like ...
- What methods does this class have?
- What are its parents?
- What attributes does it have (including inherited attributes)?
- What roles does it do?
- Much, much, more
Moose Meta-API
- Not just for introspection ...
- Add methods, attributes, roles, etc
- Extend and alter core features
Why Moose?
- A quick bit of propaganda ...
With Moose
package Person;
use Moose;
has last_name => (
is => 'rw',
isa => 'Str',
);
Without Moose
package Person;
use strict;
use warnings;
use Carp 'confess';
sub new {
my $class = shift;
my %args = @_;
my $self = {};
if (exists $args{last_name}) {
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $args{last_name}"
if ref($args{last_name});
$self->{last_nane} = $args{last_name};
}
return bless $self, $class;
}
sub last_name {
my $self = shift;
if (@_) {
my $value = shift;
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $value"
if ref($value);
$self->{last_name} = $value;
}
return $self->{last_name};
}
Side by side
package Person;
use Moose;
has last_name => (
is => 'rw',
isa => 'Str',
);
|
package Person;
use strict;
use warnings;
use Carp 'confess';
sub new {
my $class = shift;
my %args = @_;
my $self = {};
if (exists $args{last_name}) {
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $args{last_name}"
if ref($args{last_name});
$self->{last_nane} = $args{last_name};
}
return bless $self, $class;
}
sub last_name {
my $self = shift;
if (@_) {
my $value = shift;
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $value"
if ref($value);
$self->{last_name} = $value;
}
return $self->{last_name};
}
|
Side by side
package Person;
use Moose;
has last_name => (
is => 'rw',
isa => 'Str',
);
|
package Person;
use strict;
use warnings;
use Carp 'confess';
sub new {
my $class = shift;
my %args = @_;
my $self = {};
if (exists $args{last_name}) {
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $args{last_name}"
if ref($args{last_name});
$self->{last_nane} = $args{last_name};
}
return bless $self, $class;
}
sub last_name {
my $self = shift;
if (@_) {
my $value = shift;
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $value"
if ref($value);
$self->{last_name} = $value;
}
return $self->{last_name};
}
|
Side by side
package Person;
use Moose;
has last_name => (
is => 'rw',
isa => 'Str',
);
|
package Person;
use strict;
use warnings;
use Carp 'confess';
sub new {
my $class = shift;
my %args = @_;
my $self = {};
if (exists $args{last_name}) {
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $args{last_name}"
if ref($args{last_name});
$self->{last_nane} = $args{last_name};
}
return bless $self, $class;
}
sub last_name {
my $self = shift;
if (@_) {
my $value = shift;
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $value"
if ref($value);
$self->{last_name} = $value;
}
return $self->{last_name};
}
|
Side by side
package Person;
use Moose;
has last_name => (
is => 'rw',
isa => 'Str',
);
|
package Person;
use strict;
use warnings;
use Carp 'confess';
sub new {
my $class = shift;
my %args = @_;
my $self = {};
if (exists $args{last_name}) {
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $args{last_name}"
if ref($args{last_name});
$self->{last_nane} = $args{last_name};
}
return bless $self, $class;
}
sub last_name {
my $self = shift;
if (@_) {
my $value = shift;
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $value"
if ref($value);
$self->{last_name} = $value;
}
return $self->{last_name};
}
|
Side by side
package Person;
use Moose;
has last_name => (
is => 'rw',
isa => 'Str',
);
|
package Person;
use strict;
use warnings;
use Carp 'confess';
sub new {
my $class = shift;
my %args = @_;
my $self = {};
if (exists $args{last_name}) {
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $args{last_name}"
if ref($args{last_name});
$self->{last_nane} = $args{last_name};
}
return bless $self, $class;
}
sub last_name {
my $self = shift;
if (@_) {
my $value = shift;
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $value"
if ref($value);
$self->{last_name} = $value;
}
return $self->{last_name};
}
|
Side by side
package Person;
use Moose;
has last_name => (
is => 'rw',
isa => 'Str',
);
|
package Person;
use strict;
use warnings;
use Carp 'confess';
sub new {
my $class = shift;
my %args = @_;
my $self = {};
if (exists $args{last_name}) {
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $args{last_name}"
if ref($args{last_name});
$self->{last_nane} = $args{last_name};
}
return bless $self, $class;
}
sub last_name {
my $self = shift;
if (@_) {
my $value = shift;
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $value"
if ref($value);
$self->{last_name} = $value;
}
return $self->{last_name};
}
|
Side by side
| 5 lines |
21 lines |
| 92 characters |
741 characters |
package Person;
use Moose;
has last_name => (
is => 'rw',
isa => 'Str',
);
|
package Person;
use strict;
use warnings;
use Carp 'confess';
sub new {
my $class = shift;
my %args = @_;
my $self = {};
if (exists $args{last_name}) {
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $args{last_name}"
if ref($args{last_name});
$self->{last_nane} = $args{last_name};
}
return bless $self, $class;
}
sub last_name {
my $self = shift;
if (@_) {
my $value = shift;
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $value"
if ref($value);
$self->{last_name} = $value;
}
return $self->{last_name};
}
|
Typo?
sub new {
my $class = shift;
my %args = @_;
my $self = {};
if (exists $args{last_name}) {
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $args{last_name}"
if ref($args{last_name});
$self->{last_nane} = $args{last_name};
}
return bless $self, $class;
}
Typo?
if (exists $args{last_name}) {
confess "Attribute (last_name) does not pass the type constraint because: "
. "Validation failed for 'Str' with value $args{last_name}"
if ref($args{last_name});
$self->{last_nane} = $args{last_name};
}
Typo?
$self->{last_nane} = $args{last_name};
Typo?
$self->{last_nane}
Why Moose?
package Person;
use Moose;
has last_name => (
is => 'rw',
isa => 'Str',
);
More Why Moose?
- Less code == fewer bugs
- Moose is well-tested, test your own code, not Moose
- Focus on what, not how
Part 1: Moose Classes
Moose Classes
- Moose classes are Perl packages which
use Moose
Moose.pm and Your Class
package Person;
use Moose;
Moose.pm
provides declarative sugar
- Turns on
strict
and warnings
- Creates metaclasses for your class:
Person->meta
- Moose classes automatically inherit from
Moose::Object
What Moose::Object
Provides
- Constructor -
new()
- Calls your
BUILDARGS()
and/or BUILD()
- Calls your
DEMOLISH
during object destruction
BUILDARGS
- Processes
new
's @_
, returns a hash reference of attribute name/value pairs
- Accepts a hash or hashref; errors otherwise
- Provide your own for other cases
- Always call
$class->SUPER::BUILDARGS(@_)
as a fallback!
BUILDARGS Example
package Person;
use Moose;
sub BUILDARGS {
my $class = shift;
if ( @_ == 1 && ! ref $_[0] ) {
return { ssn => $_[0] };
}
return $class->SUPER::BUILDARGS(@_);
}
Person->new('123-45-6789')
BUILD
- Called after object is created, before
new
returns
- Chance to do more complex validation, set complex attributes
- Called in reverse inheritance order, parents to children
- Return value is ignored
BUILD Example
package Person;
use Moose;
sub BUILD {
my $self = shift;
if ( $self->country_of_residence
eq 'USA' ) {
die 'All US residents'
. ' must have an SSN'
unless $self->has_ssn;
}
}
Object Construction a la Moose
Person->new(@args)
- Calls
Person->BUILDARGS(@args)
to turn @args
into a hashref
- Blesses a reference
- Populates attributes based on the hashref from #1
- Calls
$new_object->BUILDALL($constructor_args)
... which calls all BUILD
methods
- Returns the object
The Object is Opaque
- Technically it's a hash reference
- If you ever treat it as one you are doing it wrong!
- Moose probably provides a feature to do what you need
DEMOLISH
- Like
DESTROY
, but Moose makes sure all DEMOLISH
methods in a hierarchy are called
- Called in normal inheritance order, children to parents
- Never called by you, only by Perl itself
extends
extends
is sugar for declaring parent classes
- Also ensures metaclass compatibility between parent and child
- Do not
use base
package Employee;
use Moose;
extends 'Person';
extends
- Each call to
extends
resets your parents
Wrong
package EvilEmployee;
use Moose;
extends 'Person';
extends 'Thief';
Right
package EvilEmployee;
use Moose;
extends 'Person', 'Thief';
Extending un-Moose-y Parents
package My::LWP;
use Moose;
extends 'LWP';
- No
Moose::Object
, so ...
- No attribute-handling
new()
- No
BUILDARGS()
or BUILD()
- No
DEMOLISH()
- But
MooseX::NonMoose
fixes all of this
override
and super
override
is another method modifier
- An alternative to Perl's
SUPER::
- Declares your intent to override a method
override
and super
package Employee;
use Moose;
extends 'Person';
override work => sub {
my $self = shift;
die "Pay me first"
unless $self->got_paid;
return super();
};
Caveat super
- Mostly like
$self->SUPER::work(@_)
- But cannot change
@_
!
- Binds the parent's method correctly at compile time
- Parent determined by checking
Child->meta()->superclasses()
Minimal Attributes
has 'foo'
- Use
is => 'ro'
or is => 'rw'
- Attributes without "is" have no accessors
Read-write attributes
package Person;
use Moose;
has first_name => ( is => 'rw' );
my $person =
Person->new( first_name => 'Dave' );
$person->first_name('Stevan');
print $person->first_name; # Stevan
Read-only attributes
package Person;
use Moose;
has first_name => ( is => 'ro' );
my $person =
Person->new( first_name => 'Dave' );
$person->first_name('Stevan'); # dies
Declaring Attributes Creates Methods
has first_name => ( is => 'ro' );
creates a first_name()
method
- This returns the value of the attribute
- With read-write attributes, you can also pass a value to set the attribute
There is More to Come
- Attributes have a lot of features
Cleaning Up Moose Droppings
package Person;
use Moose;
# true
Person->can('extends');
Cleaning Up Moose Droppings
package Person;
use Moose;
...
no Moose;
# false
Person->can('extends');
Cleaning Up Moose Droppings
package Person;
use Moose;
use namespace::autoclean;
...
# false
Person->can('extends');
No Moose
- Cleaning up is a best practice
- Say
no Moose
at the end of a package
- Or
use namespace::autoclean
at the top
- Just do it
Immutability
- Stevan's Incantation of Fleet-Footedness
package Person;
use Moose;
__PACKAGE__->meta->make_immutable;
What make_immutable
does
- Magic
- Uses
eval
to "inline" a constructor
- Memoizes a lot of meta-information
- Makes loading your class slower
- Makes object creation much faster
When to Immutabilize?
- Almost always
- Startup time vs execution time
Classes Summary
use Moose
Class->meta
Moose::Object
base class
extends
, override
, and super
- Simple attributes:
has
, is => 'ro'
, & is => 'rw'
no Moose
__PACKAGE__->meta->make_immutable
Questions?
Exercises
# cd exercises
# prove -lv t/00-prereq.t
## Read the instructions in t/01-classes.t
# prove -lv t/01-classes.t
# edit lib/Person.pm and lib/Employee.pm
Iterate til this passes all its tests
Part 2: Roles
Just What Is a Role?
- Mixin? Interface? Trait?
- Yes ... and more!
Roles - State and Behavior
package HasPermissions;
use Moose::Role;
# state
has access_level => ( is => 'rw' );
# behavior
sub can_access {
my $self = shift;
my $required = shift;
return $self->access_level
>= $required;
}
Roles Can Define Interfaces
package Printable;
use Moose::Role;
requires 'as_string';
Roles Can Do All Three
package Printable;
use Moose::Role;
requires 'as_string';
has has_been_printed => ( is => 'rw' );
sub print {
my $self = shift;
print $self->as_string;
$self->has_been_printed(1);
}
Classes Consume Roles
package Person;
use Moose;
with 'Printable';
# required by role
sub as_string { $_[0]->first_name() }
Classes Consume Roles
my $person = Person->new(
first_name => 'Kenichi',
last_name => 'Asai',
access_level => 42,
);
$person->print(); # prints 'Kenichi'
Roles in Practice
- Consuming a role =~ inlining the role
In Other Words ...
package Person;
use Moose;
with 'Printable';
sub as_string { $_[0]->first_name() }
In Other Words ...
package Person;
use Moose;
with 'Printable';
sub as_string { $_[0]->first_name() }
has has_been_printed => ( is => 'rw' );
sub print {
my $self = shift;
print $self->as_string;
$self->has_been_printed(1);
}
Except
- Role consumption is introspectable
if ( Person->does('Printable') ) { ... }
# or ...
Person->meta->does_role('Printable')
These Names Are the Same
- What if a role and class define the same method?
- A class's local methods win over the role's
- The role's methods win over the class's inherited methods
Conflicts Between Roles
- Two roles with a method of the same name
- Generates a compile-time error when consumed by a class
Conflict Example
package IsFragile;
use Moose::Role;
sub break { ... }
package CanBreakdance;
use Moose::Role;
sub break { ... }
Conflict Example
package FragileDancer;
use Moose;
with 'IsFragile', 'CanBreakdance';
Conflict Resolution
- The consuming class must resolve the conflict by implementing the method
- Can use some combination of method exclusion and aliasing
Conflicts Are a Smell
- Roles are about semantics!
- Roles have a meaning
- Method name conflicts smell like bad design
Roles With Roles
package Comparable;
use Moose::Role;
requires 'compare';
Roles With Roles
package TestsEquality;
use Moose::Role;
with 'Comparable';
sub is_equal {
my $self = shift;
return $self->compare(@_) == 0;
}
And then ...
package Integer;
use Moose;
with 'TestsEquality';
# Satisfies the Comparable role
sub compare { ... }
Integer->does('TestsEquality'); # true
Integer->does('Comparable'); # also true!
Roles as Interfaces
- Roles can require their consumers to implement methods with
requires
- Compile-time checks
- Method must exist when the role is consumed
The Attribute Gotcha
package HasSize;
use Moose::Role;
requires 'size';
package Shirt;
use Moose;
with 'HasSize';
has size => ( is => 'ro' );
The Attribute Gotcha Workaround
package HasSize;
use Moose::Role;
requires 'size';
package Shirt;
use Moose;
has size => ( is => 'ro' );
with 'HasSize';
Compile-time Is a Lie
- Really, it's package load time
- That's run-time, but before the "real" run-time
- Moose does not rewire Perl, it's just sugar!
- (but
Moops
does rewire Perl)
Enforcing Roles
package Comparison;
use Moose;
has [ 'left', 'right' ] => (
is => 'ro',
does => 'Comparable',
);
- A sneak peek at type constraints
Roles Can Be Applied to Objects
use Moose::Util qw( apply_all_roles );
my $fragile_person = Person->new( ... );
apply_all_roles( $fragile_person,
'IsFragile' );
- Does not change the
Person
class
- Works with non-Moose classes, great for monkey-patching!
Roles Are Dirty Too
- Once again, clean up those Moose droppings
package Comparable;
use Moose::Role;
requires 'compare';
no Moose::Role;
- But roles cannot be made immutable
The Zen of Roles
- Roles represent discrete units of ...
- Roles are shareable between unrelated classes
- Roles are what a class does, not what it is
- Roles add functionality, inheritance specializes
Abstract Examples
- Human @ISA Animal
- Human does Toolmaker (as does Chimpanzee)
- Car @ISA Vehicle
- Car does HasEngine
Real Examples
- Objects representing SQL database components and queries
- Schema, Table, Column, ColumnAlias
- Select, Insert, Update, Delete
Real Examples
- All queries do HasWhereClause
- Select does Comparable and Selectable (for subselects)
- A where clause requires its components to do Comparable
Roles Summary
- Roles can define an interface with
requires
- Roles can have state (attributes) and behavior (methods)
- Roles can mix interface, state, & behavior
- Roles are composed (flattened) into classes
- Roles can do other roles
- Roles can be used as a type in APIs (must do Comparable)
Questions?
Exercises
# cd exercises
# prove -lv t/02-roles.t
Iterate til this passes all its tests
Part 3: Basic Attributes
Attributes Are Huge
- Moose's biggest feature
- The target of many MooseX modules
Quick Review
- Declared with
has
- Read-only or read-write
package Shirt;
use Moose;
has 'color' => ( is => 'ro' );
has 'is_ripped' => ( is => 'rw' );
Read-only vs Read-write
- Read-only is preferred
- Minimize state in your application
Required-ness
- Required means "must be passed to the constructor"
- But can be
undef
Required-ness
package Person;
use Moose;
has first_name => (
is => 'ro',
required => 1,
);
Person->new( first_name => undef ); # ok
Person->new(); # kaboom
Default and Builder
- Attributes can have defaults
- Simple non-reference scalars (number, string)
- Subroutine reference
- A builder method
Default
- Can be a non-reference scalar (including
undef
)
package Person;
use Moose;
has bank => (
is => 'rw',
default => 'Spire FCU',
);
Default
- Can be a subroutine reference
package Person;
use Moose;
has bank => (
is => 'rw',
default =>
sub { Bank->new(
name => 'Spire FCU' ) },
);
Subroutine Reference Default
- Called as a method on the object
- Called anew for each object
Why No Other Reference Types?
package Person;
use Moose;
has bank => (
is => 'rw',
# THIS WILL NOT WORK
default => Bank->new(
name => 'Spire FCU' ),
);
- Now every person shares the same Bank object!
Defaulting to an Empty Reference
package Person;
use Moose;
has packages => (
is => 'rw',
default => sub { [] },
);
Builder
- A method name
- When called, this method returns the default value
Builder
package Person;
use Moose;
has bank => (
is => 'rw',
builder => '_build_bank',
);
sub _build_bank {
my $self = shift;
return Bank->new(
name => 'Spire FCU' );
}
Default vs Builder
- Use default for simple scalars
- Use default to return empty references
- Use default for very trivial subroutine references
- Use builder for everything else
Builder Bonuses
- Can be overridden and method modified, because it's called by name
- Roles can require a builder
Role Requires Builder
package HasBank;
use Moose::Role;
requires '_build_bank';
has bank => (
is => 'ro',
builder => '_build_bank',
);
Lazy, Good for Nothin' Attributes
- Normally, defaults are generated during object construction
- This can be expensive
- We want to default to
$self->size * 2
, but attribute initialization order is unpredictable
- Use lazy attributes!
The Power of Dynamic Defaults
package Person;
use Moose;
has shoe_size => (
is => 'ro',
required => 1,
);
The Power of Dynamic Defaults
has shoes => (
is => 'ro',
lazy => 1,
builder => '_build_shoes',
);
sub _build_shoes {
my $self = shift;
return Shoes->new(
size => $self->shoe_size );
}
Lazy is Good
- Lazy defaults are executed when the attribute is read
- Can see other object attributes
- Still need to watch out for circular laziness
Clearer and Predicate
- Attributes can have a value, including
undef
, or not
- Can clear the value with a clearer method
- Can check for the existence of a value with a predicate method
- By default, these methods are not created
Clearer and Predicate
package Person;
use Moose;
has account => (
is => 'ro',
lazy => 1,
builder => '_build_account',
clearer => '_clear_account',
predicate => 'has_account',
);
Clearer and Lazy Defaults
- Lazy defaults are good for computed attributes
- Clear the attribute when the source data changes
- Recalculated at next access
Renaming constructor arguments
- By default, constructor names = attribute names
- Use
init_arg
to change this
- Set
init_arg => undef
to make it unconstructable
Some init_arg
examples
package Person;
use Moose;
has shoe_size => (
is => 'ro',
init_arg => 'foot_size',
);
Person->new( shoe_size => 13 );
my $person =
Person->new( foot_size => 13 );
print $person->shoe_size;
Some init_arg
examples
package Person;
use Moose;
has shoes => (
is => 'ro',
init_arg => undef,
);
Person->new( shoes => Shoes->new );
Some More init_arg
examples
- Private attribute, public constructor name
package Person;
use Moose;
has _size => (
is => 'ro',
init_arg => 'size',
);
my $person = Person->new( size => 42 );
$person->size(); # error
Why Set init_arg => undef
?
- Use this with a lazy default for attributes-as-cache
- Compute the value as needed
- Ensure that it is always generated correctly (not set by constructor)
- Use triggers or method modifiers (coming soon) to clear the value
Attribute Inheritance
- By default, subclasses inherit attributes as-is
- Can change attribute parameters in subclasses
Attribute Inheritance Example
package Employee;
use Moose;
extends 'Person';
has '+first_name' => (
default => 'Joe',
);
Attribute Inheritance Warning
- An attribute is a contract about a class's API
- Don't break that contract in a subclass
- Especially important in the context of types
Changing Accessor Names
package Person;
use Moose;
has first_name => (
accessor => 'first_name',
);
- The long-hand version of
is => 'rw'
Changing Accessor Names
package Person;
use Moose;
has first_name => (
reader => 'first_name',
writer => undef,
);
- The long-hand version of
is => 'ro'
Changing Accessor Names
package Person;
use Moose;
has first_name => (
reader => 'get_first_name',
writer => 'set_first_name',
);
Changing Accessor Names
package Person;
use Moose;
has first_name => (
is => 'rw',
writer => '_first_name',
);
- Can also mix-and-match
is
and explicit names
ETOOMUCHTYPING
MooseX::FollowPBP
get_foo
and set_foo
MooseX::SemiAffordanceAccessor
foo
and set_foo
ETOOMUCHTYPING
package Person;
use Moose;
use MooseX::SemiAffordanceAccessor;
has first_name => (
is => 'rw',
);
- Creates
first_name
and set_first_name
Basic Attributes Summary
- Attributes can be
required
- Attributes can have a
default
or builder
- Attributes with a default or builder can be
lazy
- Attributes can have a
clearer
and/or predicate
Basic Attributes Summary
- An attribute's constructor name can be changed with
init_arg
- A subclass can alter its parents' attributes
- Attribute accessor names can be changed
Questions?
Exercises
# cd exercises
# prove -lv t/03-basic-attributes.t
Iterate til this passes all its tests
Part 4: Method Modifiers
What is a Method Modifier
- Apply to an existing method
- ... that comes from a parent class, the current class, or a role
- Roles can provide modifiers that are applied at composition time
What Are Method Modifiers For?
- "Inject" behavior
- Add behavior to generated methods (accessors, delegations)
- Added from a role, can modify existing behavior
Before and After
- Simplest modifiers -
before
and after
- Guess when they run!
Uses for before
package Person;
use Moose;
before work => sub {
my $self = shift;
die 'I have no job!'
unless $self->has_title;
};
Uses for before
package Person;
use Moose;
before work => sub {
my $self = shift;
return unless $DEBUG;
warn "Called work on ",
$self->full_name,
"with the arguments: [@_]\n";
};
Uses for after
- Also works for logging/debugging
- Post-X side-effects (recording audit info)
package Person;
use Moose;
after work => sub {
my $self = shift;
$self->work_count(
$self->work_count + 1 );
};
Other Uses
- Modifiers are useful for adding behavior to generated methods
More Modifier Examples
has password => (
is => 'rw',
clearer => 'clear_password',
);
has hashed_password => (
is => 'ro',
builder => '_build_hashed_password',
clearer => '_clear_hashed_password',
);
after clear_password => sub {
my $self = shift;
$self->_clear_hashed_password;
};
before
and after
Limitations
- Cannot alter method parameters
- Cannot alter return value
- But can throw an exception
The around
Modifier
- The big gun
- Can alter parameters and/or return values
- Can skip calling the wrapped method entirely
The power of around
around insert => sub {
my $orig = shift;
my $self = shift;
$self->_validate_insert(@_);
my $new_user =
$self->$orig(
$self->_munge_insert(@_) );
$new_user->_assign_uri;
return $new_user;
};
Modifier Order
- Before runs in order from last to first
- After runs in order from first to last
- Around runs in order from last to first
Modifier Order Illustrated
before 2
before 1
around 2
around 1
wrapped method
around 1
around 2
after 1
after 2
Modifiers in Roles
- Roles can use these modifiers
- Very powerful!
Modifiers in Roles
package IsUnreliable;
use Moose::Role;
requires 'run';
around run => sub {
my $orig = shift;
my $self = shift;
return if rand(1) < 0.5;
return $self->$orig(@_);
};
Method Modifiers Summary
- Use
before
and after
for ...
- logging
- pre- or post-validation
- to add behavior to generated methods
- These two modifiers cannot change parameters or return values
Method Modifiers Summary
- Use
around
to ...
- alter parameters passed to the original method
- alter the return value of the original method
- not call the original method at all (or call a different method)
- When using modifiers in a role, require the modified method
Questions?
Exercises
# cd exercises
# prove -lv t/04-method-modifiers.t
Iterate til this passes all its tests
Part 5: Types
A Type System for Perl
- Sort of ...
- Variables are not typed
- Attributes can have types
- MooseX modules let you define method signatures
Components of a Moose Type
- A type is a name and a constraint
- Types have a hierarchy
- Constraints are cumulative from parents
- Types can have associated coercions
Built-in Type Hierarchy
Any
Item
Bool
Maybe[`a]
Undef
Defined
Value
Str
Num
Int
ClassName
RoleName
Built-in Type Hierarchy
(Item)
(Defined)
(Value)
Ref
ScalarRef
ArrayRef[`a]
HashRef[`a]
CodeRef
RegexpRef
GlobRef
FileHandle
Object
Bool
True
1
False
0
'0'
''
undef
Value (and subtypes)
Value
is true when ! ref $thing
Value
and Str
are effectively the same, but Str
is more expressive
Num
is true when a $scalar
looks like a number
- An overloaded object which numifies does not pass the
Num
constraint!
- Perl 5's overloading is hopelessly broken
ClassName and RoleName
- A string with a package name
- The package must already be loaded
Parameterizable Types
- What does
ArrayRef[`a]
mean?
s/`a/Int/
(or Str
or ...)
- When you use it you can write ...
ArrayRef
(== ArrayRef[Item]
)
ArrayRef[Str]
ArrayRef[MyTypeName]
ArrayRef[HashRef[Maybe[Int]]]
Maybe[`a]
- Maybe means either the named type or
undef
Maybe[Int]
accepts integers or undef
Type Union
- This or that (or that or ...)
Int | ArrayRef[Int]
- But use a coercion instead when possible
- Or use a
role_type
, duck_type
, or anything not a union
- A union is often a code smell
Making Your Own Types
use Moose::Util::TypeConstraints;
subtype 'PositiveInt',
as 'Int',
where { $_ > 0 },
message
{ "The value you provided ($_)"
. " was not a positive int." };
has size => (
is => 'ro',
isa => 'PositiveInt',
);
Automatic Types
- Moose creates a type for every Moose class and role
- Unknown names are assumed to be classes
Automatic Types
package Employee;
use Moose;
has manager => (
is => 'rw',
isa => 'Employee',
);
has start_date => (
is => 'ro',
isa => 'DateTime',
);
Subtype Shortcuts - class_type
use Moose::Util::TypeConstraints;
class_type 'DateTime';
subtype 'DateTime',
as 'Object',
where { $_->isa('DateTime') },
message { ... };
Subtype Shortcuts - role_type
use Moose::Util::TypeConstraints;
role_type 'Printable';
subtype 'Printable',
as 'Object',
where
{ Moose::Util::does_role(
$_, 'Printable' ) },
message { ... };
Subtype Shortcuts - duck_type
use Moose::Util::TypeConstraints;
duck_type Car => qw( run break_down );
subtype 'Car',
as 'Object',
where { all { $_->can($_) }
qw( run break_down ) },
message { ... };
Subtype Shortcuts - enum
use Moose::Util::TypeConstraints;
enum Color => qw( red blue green );
my %ok = map { $_ => 1 }
qw( red blue green );
subtype 'Color',
as 'Str',
where { $ok{$_} },
message { ... };
Anonymous Subtypes
package Person;
my $posint =
subtype
as 'Int',
where { $_ > 0 };
has size => (
is => 'ro',
isa => $posint,
);
- Shortcuts have anonymous forms as well
Coercions
use Moose::Util::TypeConstraints;
subtype 'UCStr',
as 'Str',
where { ! /[a-z]/ };
Coercions
coerce 'UCStr',
from 'Str',
via { uc };
has shouty_name => (
is => 'ro',
isa => 'UCStr',
coerce => 1,
);
Coercion Examples
subtype 'My::DateTime',
as class_type 'DateTime';
coerce 'My::DateTime',
from 'HashRef',
via { DateTime->new( %{$_} ) };
coerce 'My::DateTime',
from 'Int',
via { DateTime->from_epoch(
epoch => $_ ) };
- Use coercion to inflate a value
Coercion Examples
# BAD CODE - DO NOT COPY
coerce 'ArrayRef[Int]',
from 'Int',
via { [ $_ ] };
- Instead of union -
Int | ArrayRef[Int]
Using Types with Attributes
package Person;
has height => (
is => 'rw',
isa => 'Num',
);
has favorite_numbers => (
is => 'rw',
isa => 'ArrayRef[Int]',
coerce => 1,
);
More Droppings
Moose::Util::TypeConstraints
also needs cleanup
package Person;
use Moose;
use Moose::Util::TypeConstraints;
subtype ...;
no Moose;
no Moose::Util::TypeConstraints;
Questions So Far?
Exercises
# cd exercises
# prove -lv t/05-types.t
Iterate til this passes all its tests
Typed Methods (Low-tech)
package Person;
use MooseX::Params::Validate qw( validated_list );
sub work {
my $self = shift;
my ( $tasks, $can_rest ) =
validated_list(
\@_,
tasks =>
{ isa => 'ArrayRef[Task]',
coerce => 1 },
can_rest =>
{ isa => 'Bool',
default => 0 },
);
...
}
Typed Methods (High-tech)
package Person;
use MooseX::Method::Signatures;
method work ( ArrayRef[Task] :$tasks,
Bool :$can_rest = 0 ) {
my $self = shift;
...
}
Digression: The Type Registry
- Types are actually
Moose::Meta::TypeConstraint
objects
- Stored in an interpreter-global registry mapping names to objects
Danger!
- Coercions are attached to type objects
- Therefore also global
- Name conflicts between modules!
- Coercion conflicts between modules!
Namespace Fix
- Use some sort of pseudo-namespacing scheme
- Never coerce directly to a class name, or to built-in types
Namespace Fix
use Moose::Util::TypeConstraints;
subtype 'MyApp::Type::DateTime',
as 'DateTime';
coerce 'MyApp::Type::DateTime',
from 'HashRef',
via { DateTime->new( %{$_} ) }
has creation_date => (
is => 'ro',
isa => 'MyApp::Type::DateTime',
coerce => 1,
);
Namespace Fix
subtype 'MyApp::Type::ArrayOfInt',
as 'ArrayRef[Int]';
coerce 'MyApp::Type::ArrayOfInt',
from 'Int',
via { [ $_ ] };
Namespace Fix Pros and Cons
- Relatively simple
- Already built into Moose
- Conflates type and module namespaces
- Type names are strings, so typos are easy to make and may be hard to find
MooseX::Types
package MyApp::Types;
use MooseX::Types
-declare => [ qw( ArrayOfInt ) ];
use MooseX::Types::Moose
qw( ArrayRef Int );
subtype ArrayOfInt,
as ArrayRef[Int];
coerce ArrayOfInt
from Int,
via { [ $_ ] };
MooseX::Types
package MyApp::Account;
use MyApp::Types qw( ArrayOfInt );
has transaction_history => (
is => 'rw',
isa => ArrayOfInt,
);
MooseX::Types
- Type names are exported functions, catches typos early
- Types must be pre-declared
- Types are stored with namespaces internally, but you use short names
- Import existing Moose types as functions from
MooseX::Types::Moose
- Still need string names for things like
ArrayRef['Email::Address']
MooseX::Types Pros and Cons
- Catches typos at compile time
- Automatic namespacing
- One more thing to install and learn
- Every name is typed twice (declared and then defined)
- Still stuck with strings when referring to class or role names
- Coercion gotcha from earlier still applies to types exported from
MooseX::Types::Moose
Type::Tiny
- Toby Inkster's module
- Works with Moose and Moo
- Matches the Moose and MooseX::Types APIs exactly (this is not necessarily a good thing)
Recommendation
- Use
MooseX::Types
or Type::Tiny
for now
- Maybe try out my module
Specio
- Compile time error catching and automatic namespacing are huge wins
- Docs from
Moose::Util::TypeConstraints
are 98% compatible with MooseX::Types
anyway
- A function exported by a type library works wherever a type name would
Questions?
Part 6: Advanced Attributes
Weak References
- A weak reference lets you avoid circular references
- Weak references do not increase the reference count
Circular Reference Illustrated
my $foo = {};
my $bar = { foo => $foo };
$foo->{bar} = $bar;
- Neither
$foo
nor $bar
go out of scope
(until the program exits)
Weakening Circular References
use Scalar::Util qw( weaken );
my $foo = {};
my $bar = { foo => $foo };
$foo->{bar} = $bar;
weaken $foo->{bar}
- When
$bar
goes out of scope, $foo->{bar}
becomes undef
Circular References in Attributes
package Person;
use Moose;
has name => ( is => 'ro' );
has friend => ( is => 'rw' );
my $alice = Person->new( name => 'Alice' );
my $bob = Person->new( name => 'Bob' );
$bob->friend($alice);
$alice->friend($bob);
The Fix
package Person;
use Moose;
has name => ( is => 'ro' );
has friend => ( is => 'rw',
weak_ref => 1 );
my $alice = Person->new( name => 'Alice' );
my $bob = Person->new( name => 'Bob' );
$bob->friend($alice);
$alice->friend($bob);
Under the Hood
- A
weak_ref
attribute calls weaken
...
- during object construction
- when the attribute is set via a writer
Triggers
- A code reference run after an attribute is set
- Like an
after
modifier, but makes intentions clearer
Gross
after salary_level => {
my $self = shift;
return unless @_;
$self->clear_salary;
};
Use a Trigger Instead
Cleaner
has salary_level => (
is => 'rw',
trigger =>
sub { $_[0]->clear_salary },
);
Trigger Arguments
$self
$new_value
$old_value
- if one exists
Delegation
- Attributes can be objects
- Delegation transparently calls methods on those objects
Delegation Examples
package Person;
has lungs => (
is => 'ro',
isa => 'Lungs',
handles => [ 'inhale', 'exhale' ],
);
- Creates
$person->inhale
and ->exhale
methods
- Internally calls
$person->lungs->inhale
Delegation Explained
package Person;
has lungs => (
is => 'ro',
isa => 'Lungs',
handles => [ 'inhale', 'exhale' ],
);
sub inhale {
my $self = shift;
$self->lungs()->inhale();
}
sub exhale { ... }
Why Delegation?
- Reduce the number of classes exposed
- Re-arrange class internals -
turn a method into an attribute with delegation
- Provide convenenience methods
Moose's handles
Parameter
- Accepts many arguments ...
- Array reference - list of methods to delegate as-is
- Hash reference - map of method names
- Regex - delegates all matching methods
- Role name - delegates all methods in the role
- Sub reference - does something complicated ;)
Array Reference
- 1-to-1 mapping
- Takes each method name and creates a simple delegation from the delegating class to the delegatee attribute
Hash Reference
- Mapping of names in the delegating class to the delegatee class
package Person;
use Moose;
has account => (
is => 'ro',
isa => 'BankAccount',
handles => {
receive_money => 'deposit',
give_money => 'withdraw',
},
);
Hash Reference Detailed
handles => {
receive_money => 'deposit',
give_money => 'withdraw',
},
$person->receive_money
= $person->account->deposit
$person->give_money
= $person->account->withdraw
Regex
package Person;
use Moose;
has name => (
is => 'ro',
isa => 'Name',
handles => qr/.*/,
);
- Creates a delegation for every method in the Name class
- Excludes
meta
and methods inherited from Moose::Object
Role Name
package Auditor;
use Moose::Role;
sub record_change { ... }
sub change_history { ... }
package Account;
use Moose;
has history => (
is => 'ro',
does => 'Auditor',
handles => 'Auditor',
);
Role Name Detailed
- Account gets delegate methods for each method in the
Auditor
role
- record_history
- change_history
Native Delegation
- Delegate to unblessed Perl types
- Scalar, array or hash ref, etc
- Treat Perl types as objects
- Still uses
handles
- Pretend that native Perl types have methods
Native Delegation - Array(Ref)
- Methods include:
push
shift
elements
- returns all elements
count
is_empty
- quite a few more
Native Delegation - Array(Ref)
package Person;
use Moose;
has _favorite_numbers => (
traits => [ 'Array' ],
isa => 'ArrayRef[Int]',
default => sub { [] },
init_arg => undef,
handles =>
{ favorite_numbers => 'elements',
add_favorite_number => 'push',
},
);
Native Delegation - Array(Ref)
my $person = Person->new();
$person->add_favorite_number(7);
$person->add_favorite_number(42);
print "$_\n"
for $person->favorite_numbers;
# 7
# 42
Native Delegation
- Native types are ...
- Number -
add
, mul
, ...
- String -
append
, chop
, ...
- Counter -
inc
, dec
, ...
- Bool -
set
, toggle
, ...
- Hash -
get
, set
, ...
- Array - already saw it
- Code -
execute
and execute_method
Curried Delegation
- A delegation with some preset arguments
- Works with object or Native delegation
Curried Delegation
package Person;
use Moose;
has account => (
is => 'ro',
isa => 'BankAccount',
handles => {
receive_100 =>
[ 'deposit', 100 ],
give_100 =>
[ 'withdraw', 100 ]
},
);
Curried Delegation
$person->receive_100;
# really is
$person->account->deposit(100);
Advanced Attributes Summary
- Use
weak_ref
to avoid circular references
- Use trigger to do an action post-attribute write
- Use delegations to hide "internal" objects
- Use native delegations to treat Perl types as objects
Questions?
Exercises
# cd exercises
# prove -lv t/06-advanced-attributes.t
Iterate til this passes all its tests
CYOA
If there is time, keep going ...
Otherwise, jump to slide 262 ...
Bonus: A Brief Tour of MooseX
Notable MX Modules on CPAN
- Not comprehensive
- 200+ MooseX distributions on CPAN as of 06/21/2014
- Some of them are crap
Already Mentioned Several
MooseX::NonMoose
- best solution for subclassing non-Moose parents
MooseX::FollowPBP
and MooseX::SemiAffordanceAccessor
MooseX::Params::Validate
and MooseX::Method::Signatures
MooseX::Types
Moops
use Moops;
use 5.14.0; # for say
class Person using Moose {
has greeting =>
( is => 'ro', isa => 'Str' );
method speak {
say $self->greeting;
}
}
Moops
- Not a source filter!
- Hooks into the Perl parser rather than filtering all your code
- But not supported by
PPI
, perltidy
, etc. (yet?)
MooseX::StrictConstructor
- By default, unknown constructor arguments are ignored
- MX::StrictConstructor turns these into an error
MooseX::StrictConstructor
package Person;
use Moose;
use MooseX::StrictConstructor;
has name => ( is => 'ro' );
Person->new
( nane => 'Ringo Shiina' ); # kaboom
MooseX::Traits
- Combines object construction and role application
- Makes it easy to create one-off customized objects
MooseX::Traits
package MyApp::Thingy;
use Moose;
with 'MooseX::Traits';
my $thing =
MyApp::Thingy->new_with_traits
( traits => [ 'Foo', 'Bar' ],
size => 42 );
MooseX::Getopt
- Makes command-line interface programs easy!
- Construct an object from CLI arguments
MooseX::Getopt
package App::CLI;
use Moose;
with 'MooseX::Getopt';
has file =>
( is => 'ro', required => 1 );
has filters =>
( is => 'ro', isa => 'ArrayRef[Str]' );
sub run { ... }
MooseX::Getopt
#!/usr/bin/perl
use App::CLI;
App::CLI->new_with_options()->run();
$ myapp-cli \
--file foo \
--filters compress \
--filters sanitize
MooseX::Clone
package Person;
use Moose;
with 'MooseX::Clone';
my $person = Person->new;
my $clone = $person->clone;
MooseX::NonMoose
- Highly recommended for subclassing non-Moose parents
- Gets all the little annoying details right
MooseX::Role::Parameterized
package HasCollection;
use MooseX::Role::Parameterized;
parameter type => ( isa => 'Str',
default => 'Item' );
role {
my $p = shift;
my $type =
'ArrayRef[' . $p->type() . ']';
has collection =>
( is => 'ro',
isa => $type );
};
MooseX::Role::Parameterized
package Person;
use Moose;
with HasCollection => { type => 'Int' };
Questions?
Moose-using Modules
For further reading, a few modules which use Moose ...
The End


In this essay I’d like to focus more on insights and deep understanding rather than memorizing specific algorithms and tricks.
And if there is one thing that lies at the heart of solving algorithm problems its recursion. Even problems that are solved iteratively have a recursive structure.
So let us consider our first problem .
Find the maximum element in an array
Now before you run off to write a for loop lets think about how to break it down recursively.
The questions you need to ask are:
The smallest instance of the problem is where the array contains a single element. This is called the base case.
We are trying to find the smallest element in the array. Say we remove the first element. Now we have a smaller sub problem which is the same as the problem we are trying to solve.
Now how do we combine the two ?
The maximum of the whole array is the max of the first element and the maximum of the rest of the array. So we simply call into the same function and the “recursion fairy” does the rest.
max_array(array):
if len(array)==1:
return array[0]
return max(array[0],max_array(array[1:]))
Notice here that we need keep track array[0] until the recursion completes. And we need to keep track of array[0] for each recursive call until we reach the end. This kind of recursion thus needs extra space.
Such a process is called a recursive process.
What if I told you that a for loop is also a kind of recursive call ?
Once you have a recursive solution one can explore how to make it iterative.
Let us try rewriting the above function in such a way that the final return statement is just a call to the same max_array function. Nothing else.
How would we do it ?
Let us think about “growing” a solution. Move from left to right and keep track of the maximum so far .
After some thinking one might write
max-iter(index,max_so_far,array):
if(index>=len(array)):
return max_so_far
else:
max-iter(index+1,max(array[index],max_so_far,array)
# To find max call it with
max-iter(1,array[0],array)
This can then be translated to a for loop formulation as
max_val = array[0]
for(index = 1; index < len(array); index++) {
max_val = max(array[index],max_val)
}
Each iteration basically calls in to the same function with an altered state. There is no need keep track of the current state. It can be discarded and we can directly jump into the recursive call with the new state. So one need not maintain a stack of the previous state.
Such a process is called an iterative process and is so common that all languages have constructs like for
and while
to make it easier.
Find the largest two elements in an array
The smallest valid instance of the problem is an array with two elements.
The largest is the max of the two and the second largest is the min of the two.
Lets try chipping off two elements and seeing if we get the same problem.
largest_two(array):
if(len(array)==2):
return(max(array[0],array[1]),min(array[0],array[1])
(largest_rest,second_largest_rest) = largest_two(array[1:])
if array[0] > largest_rest:
return (array[0],largest_rest)
if array[0] > second_largest_rest:
return (largest_rest,array[0])
else:
return (largest_rest,second_largest_rest)
Starting with the smallest instance , two elements and then grow the solution one element at a time .
largest_two(array,index,largest_so_far,second_largests_so_far):
if(index>=len(array)):
return (largest_so_far,second_largest_so_far)
if array[index] > largest_so_far:
return largest_two(array,index+1,array[index],largest_so_far)
if array[index] > second_largest_so_far:
return largest_two(array,index+1,largest_so_far,array[0])
else:
return (array,index+1,largest_so_far,second_largest_so_far)
Now this can be easily rewritten to a for loop.


1.Place a cross in the box next to Candidate's name at the top of the form overleaf 2.Place a mark or tick on checkbox for related position and party symbols


Three charged after camping and fishing store break-ins
by Staff WriterPOLICE have charged three people after an investigation into burglaries at camping and fishing stores in Jandakot, Myaree and Nedlands that occurred between October 31 and November 16.
During the burglaries high-end fishing reels valued at over $50,000 were stolen.
As part of the investigation, Fremantle Detectives executed a search warrant at a home in Strode Avenue in Hamilton Hill where it is alleged they found fishing reels, about two grams of cannabis, more than $6000 cash, three cannabis plants, 200 cannabis seeds and drug paraphernalia.
A 42-year-old man from Southern River will appear before the Fremantle Magistrates Court on December 17, charged with three counts of burglary and commit, four counts of stealing, criminal damage or destruction of property, gaining benefit by fraud and possession of methamphetamine.
A 33-year-old man and a 33-year-old woman, both of Hamilton Hill are due to appear before the Fremantle Magistrates Court on December 10.
Both have been charged with possession of stolen or unlawfully obtained property and various drug charges.


Give _view__url
a value to display a HTML document here.
If _view__url
already has a value then this page
was reached by navigating back through this window's history. In this case, click on the
refresh button in the toolbar to synchronize the contents of this window with the URL specified.
Alternatively, continue using the back or forward buttons to navigate to a more useful place in
the history.
If the toolbar is not visible then execute the following code to make it visible.
_view__toolbar_visible = true;